Merge branch 'dev' of github.com:flightaware/dump1090 into dev
This commit is contained in:
commit
29a6ae5102
5
Makefile
5
Makefile
|
|
@ -107,8 +107,11 @@ ifeq ($(RTLSDR), yes)
|
|||
# some packaged .pc files are massively broken, try to handle it
|
||||
|
||||
# FreeBSD's librtlsdr.pc includes -std=gnu89 in cflags
|
||||
# some linux librtlsdr packages return a bare -I/ with no path in --cflags
|
||||
RTLSDR_CFLAGS := $(shell pkg-config --cflags librtlsdr)
|
||||
CFLAGS += $(filter-out -std=%,$(RTLSDR_CFLAGS))
|
||||
RTLSDR_CFLAGS := $(filter-out -std=%,$(RTLSDR_CFLAGS))
|
||||
RTLSDR_CFLAGS := $(filter-out -I/,$(RTLSDR_CFLAGS))
|
||||
CFLAGS += $(RTLSDR_CFLAGS)
|
||||
|
||||
# some linux librtlsdr packages return a bare -L with no path in --libs
|
||||
# which horribly confuses things because it eats the next option on the command line
|
||||
|
|
|
|||
153
adaptive.c
153
adaptive.c
|
|
@ -33,13 +33,47 @@ static float adaptive_gain_down_db;
|
|||
//
|
||||
// block handling
|
||||
//
|
||||
// 1 block = approx 1 second of samples. Control updates are done at the end of each block only.
|
||||
// Each block is made up of an integer number of subblocks (currently 20)
|
||||
//
|
||||
// 1 subblock = approx 50ms of samples. Duty cycle decisions are made at the subblock level;
|
||||
// either the whole subblock is processed, or the whole subblock is skipped.
|
||||
// Each subblock is made up of an integer number of windows (currently 1250)
|
||||
//
|
||||
// 1 window = approx 40us of samples. Burst measurements are made by counting samples within each window.
|
||||
//
|
||||
// All three levels are aligned, i.e. every block boundary is also a subblock boundary;
|
||||
// every subblock boundary is also a window boundary.
|
||||
|
||||
static unsigned adaptive_block_remaining; // samples in each block
|
||||
static unsigned adaptive_block_size; // samples remaining in the current block
|
||||
|
||||
static const unsigned adaptive_subblocks_per_block = 20; // subblocks per block
|
||||
static unsigned adaptive_subblocks_remaining; // subblocks remaining in the current block
|
||||
|
||||
// Duty cycle is expressed as N/D
|
||||
// where N = adaptive_subblbock_dutycycle_N = adaptive_subblocks_per_block * Modes.adaptive_duty_cycle
|
||||
// and D = adaptive_subblocks_dutycycle_D = adaptive_subblocks_per_block
|
||||
//
|
||||
// i.e. within each block, there are exactly N active subblocks out of D total subblocks
|
||||
//
|
||||
// The active subblocks are distributed evenly across the block by increasing a counter by N on each
|
||||
// subblock, modulo D, and marking the subblock as active each time the counter rolls over.
|
||||
|
||||
static unsigned adaptive_subblock_dutycycle_N; // subblock duty cycle numerator N
|
||||
|
||||
// stretch gcc doesn't like this as a separate const
|
||||
#define adaptive_subblock_dutycycle_D adaptive_subblocks_per_block
|
||||
|
||||
static unsigned adaptive_subblock_dutycycle_counter; // subblock duty cycle counter (modulo D)
|
||||
static bool adaptive_subblock_active; // is the current subblock active i.e. samples should be processed, not skipped?
|
||||
|
||||
static unsigned adaptive_samples_per_subblock; // samples per subblock
|
||||
static unsigned adaptive_subblock_samples_remaining; // samples remaining in the current subblock
|
||||
|
||||
static unsigned adaptive_samples_per_window; // samples per window
|
||||
|
||||
void adaptive_init();
|
||||
void adaptive_update(uint16_t *buf, unsigned length, struct modesMessage *decoded);
|
||||
static void adaptive_update_single(uint16_t *buf, unsigned length, struct modesMessage *decoded);
|
||||
static void adaptive_update_subblock(uint16_t *buf, unsigned length, struct modesMessage *decoded);
|
||||
static void adaptive_end_of_block();
|
||||
static void adaptive_control_update();
|
||||
|
||||
|
|
@ -47,7 +81,6 @@ static void adaptive_control_update();
|
|||
// burst handling
|
||||
//
|
||||
|
||||
static unsigned adaptive_burst_window_size; // samples in each burst window
|
||||
static unsigned adaptive_burst_window_remaining; // samples remaining in the current burst window
|
||||
static unsigned adaptive_burst_window_counter; // loud samples seen in current burst window
|
||||
static unsigned adaptive_burst_runlength; // consecutive loud burst windows seen
|
||||
|
|
@ -140,14 +173,27 @@ void adaptive_init()
|
|||
if (!Modes.adaptive_burst_control && !Modes.adaptive_range_control)
|
||||
return;
|
||||
|
||||
// Set up window, subblock, and block sizes
|
||||
// Look for 40us bursts
|
||||
adaptive_burst_window_size = Modes.sample_rate / 25000;
|
||||
adaptive_burst_window_remaining = adaptive_burst_window_size;
|
||||
adaptive_burst_window_counter = 0;
|
||||
adaptive_samples_per_window = Modes.sample_rate / 25000;
|
||||
|
||||
// Use an overall block size that is an exact multiple of the burst window, close to 1 second long
|
||||
adaptive_block_size = adaptive_burst_window_size * 25000;
|
||||
adaptive_block_remaining = adaptive_block_size;
|
||||
// Use ~50ms subblocks; ensure it's an exact multiple of window size
|
||||
adaptive_samples_per_subblock = adaptive_samples_per_window * 1250;
|
||||
|
||||
adaptive_subblocks_remaining = adaptive_subblocks_per_block;
|
||||
adaptive_subblock_samples_remaining = adaptive_samples_per_subblock;
|
||||
adaptive_subblock_active = false;
|
||||
|
||||
float N = roundf(adaptive_subblock_dutycycle_D * Modes.adaptive_duty_cycle);
|
||||
if (N <= 0)
|
||||
N = 1;
|
||||
if (N > adaptive_subblock_dutycycle_D)
|
||||
N = adaptive_subblock_dutycycle_D;
|
||||
fprintf(stderr, "adaptive: using %.0f%% duty cycle\n", 100.0 * N / adaptive_subblock_dutycycle_D);
|
||||
adaptive_subblock_dutycycle_N = (unsigned)N;
|
||||
|
||||
adaptive_burst_window_remaining = adaptive_samples_per_window;
|
||||
adaptive_burst_window_counter = 0;
|
||||
|
||||
adaptive_range_radix = calloc(sizeof(unsigned), 65536);
|
||||
adaptive_range_state = RANGE_SCAN_UP;
|
||||
|
|
@ -180,26 +226,44 @@ void adaptive_update(uint16_t *buf, unsigned length, struct modesMessage *decode
|
|||
{
|
||||
if (!Modes.adaptive_burst_control && !Modes.adaptive_range_control)
|
||||
return;
|
||||
|
||||
// process samples up to a block boundary, then process the completed block
|
||||
while (length >= adaptive_block_remaining) {
|
||||
adaptive_update_single(buf, adaptive_block_remaining, decoded);
|
||||
buf += adaptive_block_remaining;
|
||||
length -= adaptive_block_remaining;
|
||||
|
||||
adaptive_end_of_block();
|
||||
adaptive_block_remaining = adaptive_block_size;
|
||||
// process complete subblocks
|
||||
while (length >= adaptive_subblock_samples_remaining) {
|
||||
if (adaptive_subblock_active)
|
||||
adaptive_update_subblock(buf, adaptive_subblock_samples_remaining, decoded);
|
||||
|
||||
buf += adaptive_subblock_samples_remaining;
|
||||
length -= adaptive_subblock_samples_remaining;
|
||||
adaptive_subblock_samples_remaining = adaptive_samples_per_subblock;
|
||||
|
||||
adaptive_subblock_dutycycle_counter += adaptive_subblock_dutycycle_N;
|
||||
if (adaptive_subblock_dutycycle_counter >= adaptive_subblock_dutycycle_D) {
|
||||
adaptive_subblock_dutycycle_counter -= adaptive_subblock_dutycycle_D;
|
||||
adaptive_subblock_active = true;
|
||||
} else {
|
||||
adaptive_subblock_active = false;
|
||||
// fake a quiet window to reset any existing run
|
||||
adaptive_burst_end_of_window(0);
|
||||
}
|
||||
|
||||
if (!--adaptive_subblocks_remaining) {
|
||||
// Block completed, do a control update
|
||||
adaptive_subblocks_remaining = adaptive_subblocks_per_block;
|
||||
adaptive_end_of_block();
|
||||
}
|
||||
}
|
||||
|
||||
// process final samples that don't complete a block
|
||||
// process final samples that don't complete a subblock
|
||||
if (length > 0) {
|
||||
adaptive_update_single(buf, length, decoded);
|
||||
adaptive_block_remaining -= length;
|
||||
if (adaptive_subblock_active)
|
||||
adaptive_update_subblock(buf, length, decoded);
|
||||
adaptive_subblock_samples_remaining -= length;
|
||||
}
|
||||
}
|
||||
|
||||
// Feed some samples into the adaptive system. The samples are guaranteed to not cross a block boundary.
|
||||
static void adaptive_update_single(uint16_t *buf, unsigned length, struct modesMessage *decoded)
|
||||
// Feed some samples into the adaptive system. The samples are guaranteed to not cross a subblock boundary.
|
||||
// The samples should be processsed (i.e. duty cycle is in the active part)
|
||||
static void adaptive_update_subblock(uint16_t *buf, unsigned length, struct modesMessage *decoded)
|
||||
{
|
||||
if (decoded) {
|
||||
if (/* decoded->msgbits == 112 && */ decoded->signalLevel >= adaptive_burst_loud_threshold)
|
||||
|
|
@ -229,8 +293,8 @@ static void adaptive_burst_skip(unsigned length)
|
|||
length -= adaptive_burst_window_remaining;
|
||||
|
||||
// skip remaining windows, dispatch them
|
||||
unsigned windows = length / adaptive_burst_window_size;
|
||||
unsigned samples = windows * adaptive_burst_window_size;
|
||||
unsigned windows = length / adaptive_samples_per_window;
|
||||
unsigned samples = windows * adaptive_samples_per_window;
|
||||
while (windows--)
|
||||
adaptive_burst_end_of_window(0);
|
||||
|
||||
|
|
@ -238,7 +302,7 @@ static void adaptive_burst_skip(unsigned length)
|
|||
|
||||
// final partial window
|
||||
adaptive_burst_window_counter = 0;
|
||||
adaptive_burst_window_remaining = adaptive_burst_window_size - length;
|
||||
adaptive_burst_window_remaining = adaptive_samples_per_window - length;
|
||||
}
|
||||
|
||||
// Burst measurement: process 'length' samples from 'buf', look for loud bursts;
|
||||
|
|
@ -265,15 +329,15 @@ static void adaptive_burst_update(uint16_t *buf, unsigned length)
|
|||
length -= n;
|
||||
|
||||
// remaining windows
|
||||
unsigned windows = length / adaptive_burst_window_size;
|
||||
unsigned samples = windows * adaptive_burst_window_size;
|
||||
unsigned windows = length / adaptive_samples_per_window;
|
||||
unsigned samples = windows * adaptive_samples_per_window;
|
||||
adaptive_burst_scan_windows(buf, windows);
|
||||
buf += samples;
|
||||
length -= samples;
|
||||
|
||||
// final partial window
|
||||
adaptive_burst_window_counter = adaptive_burst_count_samples(buf, length);
|
||||
adaptive_burst_window_remaining = adaptive_burst_window_size - length;
|
||||
adaptive_burst_window_remaining = adaptive_samples_per_window - length;
|
||||
}
|
||||
|
||||
// Burst measurement: process 'windows' complete burst windows starting at 'buf';
|
||||
|
|
@ -281,8 +345,8 @@ static void adaptive_burst_update(uint16_t *buf, unsigned length)
|
|||
static void adaptive_burst_scan_windows(uint16_t *buf, unsigned windows)
|
||||
{
|
||||
while (windows--) {
|
||||
unsigned counter = adaptive_burst_count_samples(buf, adaptive_burst_window_size);
|
||||
buf += adaptive_burst_window_size;
|
||||
unsigned counter = adaptive_burst_count_samples(buf, adaptive_samples_per_window);
|
||||
buf += adaptive_samples_per_window;
|
||||
adaptive_burst_end_of_window(counter);
|
||||
}
|
||||
}
|
||||
|
|
@ -301,7 +365,7 @@ static inline unsigned adaptive_burst_count_samples(uint16_t *buf, unsigned n)
|
|||
// loud samples seen, handle that window.
|
||||
static void adaptive_burst_end_of_window(unsigned counter)
|
||||
{
|
||||
if (counter > adaptive_burst_window_size / 4) {
|
||||
if (counter > adaptive_samples_per_window / 4) {
|
||||
// This window is loud, extend any existing run of loud windows
|
||||
++adaptive_burst_runlength;
|
||||
} else {
|
||||
|
|
@ -365,14 +429,18 @@ static void adaptive_burst_end_of_block()
|
|||
if (!Modes.adaptive_burst_control)
|
||||
return;
|
||||
|
||||
// scale rates based on the actual duty cycle fraction
|
||||
// (e.g. if we are only inspecting 2/5 of samples, then scale the rate by 5/2)
|
||||
double scale = (double)adaptive_subblock_dutycycle_D / adaptive_subblock_dutycycle_N;
|
||||
|
||||
// maintain an EMA of the number of undecoded loud bursts seen per block
|
||||
Modes.stats_current.adaptive_loud_undecoded += adaptive_burst_block_loud_undecoded;
|
||||
adaptive_burst_loud_undecoded_smoothed = adaptive_burst_loud_undecoded_smoothed * (1 - Modes.adaptive_burst_alpha) + adaptive_burst_block_loud_undecoded * Modes.adaptive_burst_alpha;
|
||||
adaptive_burst_loud_undecoded_smoothed = adaptive_burst_loud_undecoded_smoothed * (1 - Modes.adaptive_burst_alpha) + scale * adaptive_burst_block_loud_undecoded * Modes.adaptive_burst_alpha;
|
||||
adaptive_burst_block_loud_undecoded = 0;
|
||||
|
||||
// maintain an EMA of the number of decoded, but loud, messages seen per block
|
||||
Modes.stats_current.adaptive_loud_decoded += adaptive_burst_block_loud_decoded;
|
||||
adaptive_burst_loud_decoded_smoothed = adaptive_burst_loud_decoded_smoothed * (1 - Modes.adaptive_burst_alpha) + adaptive_burst_block_loud_decoded * Modes.adaptive_burst_alpha;
|
||||
adaptive_burst_loud_decoded_smoothed = adaptive_burst_loud_decoded_smoothed * (1 - Modes.adaptive_burst_alpha) + scale * adaptive_burst_block_loud_decoded * Modes.adaptive_burst_alpha;
|
||||
adaptive_burst_block_loud_decoded = 0;
|
||||
}
|
||||
|
||||
|
|
@ -464,10 +532,11 @@ static void adaptive_control_update()
|
|||
if (Modes.adaptive_range_control && !adaptive_range_change_timer) {
|
||||
float available_range = -20 * log10(adaptive_range_smoothed / 65536.0);
|
||||
// allow the gain limit to increase if this gain setting is acceptable
|
||||
// (decreasing the limit is done separately in SCAN_UP / IDLE states when we decide to reduce gain)
|
||||
if (available_range >= Modes.adaptive_range_target && current_gain > adaptive_range_gain_limit)
|
||||
// (decreasing the limit is done separately depending on the current state as we make slightly different decisions in IDLE
|
||||
// to provide hysteresis)
|
||||
if (available_range >= Modes.adaptive_range_target && current_gain > adaptive_range_gain_limit) {
|
||||
adaptive_range_gain_limit = current_gain;
|
||||
|
||||
}
|
||||
switch (adaptive_range_state) {
|
||||
case RANGE_SCAN_UP:
|
||||
if (available_range < Modes.adaptive_range_target) {
|
||||
|
|
@ -476,8 +545,9 @@ static void adaptive_control_update()
|
|||
gain_down = gain_not_up = true;
|
||||
gain_down_reason = "probing dynamic range gain lower bound";
|
||||
adaptive_range_state = RANGE_SCAN_DOWN;
|
||||
if (adaptive_range_gain_limit >= current_gain)
|
||||
if (adaptive_range_gain_limit >= current_gain) {
|
||||
adaptive_range_gain_limit = current_gain - 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -507,6 +577,10 @@ static void adaptive_control_update()
|
|||
break;
|
||||
}
|
||||
|
||||
if (adaptive_range_gain_limit >= current_gain) {
|
||||
adaptive_range_gain_limit = current_gain - 1;
|
||||
}
|
||||
|
||||
if (sdrGetGain() <= adaptive_gain_min) {
|
||||
fprintf(stderr, "adaptive: reached lower gain limit, halting dynamic range scan here\n");
|
||||
adaptive_range_state = RANGE_SCAN_IDLE;
|
||||
|
|
@ -526,8 +600,9 @@ static void adaptive_control_update()
|
|||
if (available_range + adaptive_gain_down_db / 2 < Modes.adaptive_range_target && sdrGetGain() > adaptive_gain_min) {
|
||||
fprintf(stderr, "adaptive: available dynamic range (%.1fdB) + half gain step down (%.1fdB) < required dynamic range (%.1fdB), starting downward scan\n",
|
||||
available_range, Modes.adaptive_range_target, adaptive_gain_down_db);
|
||||
if (current_gain >= adaptive_range_gain_limit)
|
||||
if (adaptive_range_gain_limit >= current_gain) {
|
||||
adaptive_range_gain_limit = current_gain - 1;
|
||||
}
|
||||
adaptive_range_state = RANGE_SCAN_DOWN;
|
||||
gain_down = gain_not_up = true;
|
||||
gain_down_reason = "dynamic range fell below target value";
|
||||
|
|
|
|||
257
comm_b.c
257
comm_b.c
|
|
@ -29,8 +29,10 @@ static int decodeBDS17(struct modesMessage *mm, bool store);
|
|||
static int decodeBDS20(struct modesMessage *mm, bool store);
|
||||
static int decodeBDS30(struct modesMessage *mm, bool store);
|
||||
static int decodeBDS40(struct modesMessage *mm, bool store);
|
||||
static int decodeBDS44(struct modesMessage *mm, bool store);
|
||||
static int decodeBDS50(struct modesMessage *mm, bool store);
|
||||
static int decodeBDS60(struct modesMessage *mm, bool store);
|
||||
static int decodeBDS05(struct modesMessage *mm, bool store);
|
||||
|
||||
static CommBDecoderFn comm_b_decoders[] = {
|
||||
&decodeEmptyResponse,
|
||||
|
|
@ -40,17 +42,18 @@ static CommBDecoderFn comm_b_decoders[] = {
|
|||
&decodeBDS17,
|
||||
&decodeBDS40,
|
||||
&decodeBDS50,
|
||||
&decodeBDS60
|
||||
&decodeBDS60,
|
||||
&decodeBDS44,
|
||||
&decodeBDS05
|
||||
};
|
||||
|
||||
void decodeCommB(struct modesMessage *mm)
|
||||
{
|
||||
mm->commb_format = COMMB_UNKNOWN;
|
||||
|
||||
// If DR or UM are set, this message is _probably_ noise
|
||||
// as nothing really seems to use the multisite broadcast stuff?
|
||||
// Also skip anything that had errors corrected
|
||||
if (mm->DR != 0 || mm->UM != 0 || mm->correctedbits > 0) {
|
||||
mm->commb_format = COMMB_NOT_DECODED;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -77,12 +80,39 @@ void decodeCommB(struct modesMessage *mm)
|
|||
// decode it
|
||||
bestDecoder(mm, true);
|
||||
}
|
||||
} else {
|
||||
mm->commb_format = COMMB_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static int decodeEmptyResponse(struct modesMessage *mm, bool store)
|
||||
{
|
||||
for (unsigned i = 0; i < 7; ++i) {
|
||||
// 00000000000000 is a common response. Ignore it.
|
||||
//
|
||||
// Also, it's common to see responses that look like this:
|
||||
// 40000000000000
|
||||
// 50000000000000
|
||||
// 60000000000000
|
||||
// typically in grouped bursts (one of each message) from
|
||||
// the same aircraft.
|
||||
//
|
||||
// I speculate that these are response to interrogations for
|
||||
// BDS 4,0 5,0 and 6,0 respectively where the transponder
|
||||
// doesn't support the register or has no data loaded for it.
|
||||
// Treat them like empty responses.
|
||||
|
||||
switch (mm->MB[0]) {
|
||||
case 0x00:
|
||||
case 0x40:
|
||||
case 0x50:
|
||||
case 0x60:
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (unsigned i = 1; i < 7; ++i) {
|
||||
if (mm->MB[i] != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -148,10 +178,10 @@ static int decodeBDS17(struct modesMessage *mm, bool store)
|
|||
score -= 2;
|
||||
}
|
||||
if (getbit(msg, 13)) { // 4,4 meterological routine report
|
||||
score -= 2;
|
||||
score -= 1;
|
||||
}
|
||||
if (getbit(msg, 14)) { // 4,4 meterological hazard report
|
||||
score -= 2;
|
||||
score -= 1;
|
||||
}
|
||||
if (getbit(msg, 20)) { // 5,4 waypoint 1
|
||||
score -= 2;
|
||||
|
|
@ -173,8 +203,11 @@ static int decodeBDS17(struct modesMessage *mm, bool store)
|
|||
} else if (!getbit(msg, 1) && !getbit(msg, 2) && !getbit(msg, 3) && !getbit(msg, 4) && !getbit(msg, 5) && !getbit(msg, 6)) {
|
||||
// not ES capable
|
||||
score += 1;
|
||||
} else if (!getbit(msg, 1) && !getbit(msg, 2) && getbit(msg, 3) && getbit(msg, 4) && getbit(msg, 5)) {
|
||||
// ES with no position data
|
||||
score += 3;
|
||||
} else {
|
||||
// partial ES support, unlikely
|
||||
// other combinations, unlikely
|
||||
score -= 12;
|
||||
}
|
||||
|
||||
|
|
@ -740,3 +773,213 @@ static int decodeBDS60(struct modesMessage *mm, bool store)
|
|||
|
||||
return score;
|
||||
}
|
||||
|
||||
// BDS4,4 Meterological routine air report
|
||||
static int decodeBDS44(struct modesMessage *mm, bool store)
|
||||
{
|
||||
unsigned char *msg = mm->MB;
|
||||
|
||||
unsigned source = getbits(msg, 1, 4);
|
||||
|
||||
unsigned wind_valid = getbit(msg, 5);
|
||||
unsigned windspeed_raw = getbits(msg, 6, 14);
|
||||
unsigned winddir_raw = getbits(msg, 15, 23);
|
||||
|
||||
// ICAO 9871 is inconsistent, it claims:
|
||||
// bit 24 sign
|
||||
// bits 25..34 static air temperature, MSB = 64C, LSB=0.25C, range -128C..+128C
|
||||
//
|
||||
// .. but this does not actually work, there is one too many bits in the bitfield
|
||||
// for the claimed values.
|
||||
//
|
||||
// Based on observed data, the most plausible actual layout is:
|
||||
//
|
||||
// bit 24 status
|
||||
// bit 25 sign
|
||||
// bits 26..34 static air temperature, MSB=64C, LSB=0.25C, range -128C..+128C
|
||||
|
||||
unsigned sat_valid = getbit(msg, 24);
|
||||
unsigned sat_sign = getbit(msg, 25);
|
||||
unsigned sat_raw = getbits(msg, 26, 34);
|
||||
|
||||
unsigned asp_valid = getbit(msg, 35);
|
||||
unsigned asp_raw = getbits(msg, 36, 46);
|
||||
|
||||
unsigned turbulence_valid = getbit(msg, 47);
|
||||
unsigned turbulence_raw = getbits(msg, 48, 49);
|
||||
|
||||
unsigned humidity_valid = getbit(msg, 50);
|
||||
unsigned humidity_raw = getbits(msg, 51, 56);
|
||||
|
||||
if (source == MRAR_SOURCE_INVALID || source >= MRAR_SOURCE_RESERVED)
|
||||
return 0; // invalid or reserved source
|
||||
|
||||
if (!wind_valid || !sat_valid)
|
||||
return 0; // all valid messages seen in the wild have at least temp + wind
|
||||
|
||||
if (!asp_valid && asp_raw != 0)
|
||||
return 0; // ASP not valid, but non-zero values in the ASP field
|
||||
|
||||
if (!turbulence_valid && turbulence_raw != 0)
|
||||
return 0; // turbulence not valid, but non-zero values in the turbulence field
|
||||
|
||||
if (!humidity_valid && humidity_raw != 0)
|
||||
return 0; // humidity not valid, but non-zero values in the humidity field
|
||||
|
||||
int score = 0;
|
||||
|
||||
float wind_speed = 0;
|
||||
float wind_dir = 0;
|
||||
if (wind_valid) {
|
||||
wind_dir = winddir_raw * (180.0 / 256.0);
|
||||
wind_speed = windspeed_raw;
|
||||
|
||||
if (windspeed_raw == 0) // possible but uncommon
|
||||
score += 2;
|
||||
else if (wind_speed <= 250)
|
||||
score += 19;
|
||||
else
|
||||
return 0;
|
||||
} else {
|
||||
score += 1;
|
||||
}
|
||||
|
||||
float sat = 0;
|
||||
if (sat_valid) {
|
||||
sat = sat_raw * 0.25;
|
||||
if (sat_sign)
|
||||
sat -= 128;
|
||||
if (sat == 0) // possible but uncommon
|
||||
score += 2;
|
||||
else if (sat >= -80 && sat <= 60)
|
||||
score += 11;
|
||||
else
|
||||
return 0;
|
||||
} else {
|
||||
score += 1;
|
||||
}
|
||||
|
||||
float asp = 0;
|
||||
if (asp_valid) {
|
||||
asp = asp_raw;
|
||||
if (asp >= 25 && asp <= 1100)
|
||||
score += 12;
|
||||
else
|
||||
return 0;
|
||||
} else {
|
||||
score += 1;
|
||||
}
|
||||
|
||||
hazard_t turbulence = HAZARD_NIL;
|
||||
if (turbulence_valid) {
|
||||
turbulence = (hazard_t) turbulence_raw;
|
||||
score += 3;
|
||||
} else {
|
||||
score += 1;
|
||||
}
|
||||
|
||||
float humidity = 0;
|
||||
if (humidity_valid) {
|
||||
humidity = humidity_raw * (100.0 / 64.0);
|
||||
score += 7;
|
||||
} else {
|
||||
score += 1;
|
||||
}
|
||||
|
||||
if (source == MRAR_SOURCE_DMEDME && wind_valid && sat_valid && score > 0) {
|
||||
// Some GICB messages can be easily mistaken for a MRAR:
|
||||
//
|
||||
// GICB bit 1: BDS 0,5 ES airborne position = 0 ]
|
||||
// GICB bit 2: BDS 0,6 ES surface position = 0 ]
|
||||
// GICB bit 3: BDS 0,7 ES status = 1 ]
|
||||
// GICB bit 4: BDS 0,8 ES type & identification = 1 ] -> MRAR source = 3
|
||||
// GICB bit 5: BDS 0,9 ES airborne velocity = 1 -> MRAR wind valid bit
|
||||
// GICB bit 24: BDS 6,0 heading and speed report = 1 -> MRAR temp valid bit
|
||||
// most trailing bits = 0
|
||||
//
|
||||
// so only treat this as MRAR as a last resort
|
||||
score = 1;
|
||||
}
|
||||
|
||||
if (store) {
|
||||
mm->commb_format = COMMB_MRAR;
|
||||
mm->mrar_source_valid = 1;
|
||||
mm->mrar_source = (mrar_source_t) source;
|
||||
|
||||
if (wind_valid) {
|
||||
mm->wind_valid = 1;
|
||||
mm->wind_speed = wind_speed;
|
||||
mm->wind_dir = wind_dir;
|
||||
}
|
||||
|
||||
if (sat_valid) {
|
||||
mm->temperature_valid = 1;
|
||||
mm->temperature = sat;
|
||||
}
|
||||
|
||||
if (asp_valid) {
|
||||
mm->pressure_valid = 1;
|
||||
mm->pressure = asp;
|
||||
}
|
||||
|
||||
if (turbulence_valid) {
|
||||
mm->turbulence_valid = 1;
|
||||
mm->turbulence = turbulence;
|
||||
}
|
||||
|
||||
if (humidity_valid) {
|
||||
mm->humidity_valid = 1;
|
||||
mm->humidity = humidity;
|
||||
}
|
||||
}
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
// BDS0,5 extended squitter airborne position
|
||||
// (apparently this gets queried via comm-b sometimes??)
|
||||
// We don't try to _use_ this as a position, but we can
|
||||
// at least try to recognize it, to exclude other
|
||||
// comm-b types (in particular they can be mistaken for MRAR)
|
||||
static int decodeBDS05(struct modesMessage *mm, bool store)
|
||||
{
|
||||
// We recognize these by matching the position altitude against
|
||||
// the altitude in the surrounding message, so we need a
|
||||
// DF20 not a DF21
|
||||
if (mm->msgtype != 20)
|
||||
return 0;
|
||||
|
||||
unsigned char *msg = mm->MB;
|
||||
|
||||
unsigned typecode = getbits(msg, 1, 5);
|
||||
if (typecode < 9 || typecode > 18)
|
||||
return 0; // only consider typecodes that could be an airborne position with baro altitude
|
||||
|
||||
unsigned t_bit = getbit(msg, 21);
|
||||
if (t_bit) // unlikely
|
||||
return 0;
|
||||
|
||||
unsigned ac12 = getbits(msg, 9, 20);
|
||||
if (!ac12)
|
||||
return 0;
|
||||
|
||||
// Insert M=0 to make an AC13 value, match against the
|
||||
// AC13 value in the surrounding message
|
||||
unsigned ac13 = ((ac12 & 0x0FC0) << 1) | (ac12 & 0x003F);
|
||||
if (mm->AC != ac13)
|
||||
return 0; // no altitude match
|
||||
|
||||
unsigned lat = getbits(msg, 23, 39);
|
||||
unsigned lon = getbits(msg, 40, 56);
|
||||
if (lat == 0 || lon == 0) // unlikely position
|
||||
return 0;
|
||||
|
||||
if (store) {
|
||||
mm->commb_format = COMMB_AIRBORNE_POSITION;
|
||||
// No further decoding done, we don't really trust this
|
||||
// enough to use as real input to CPR
|
||||
}
|
||||
|
||||
// Score this high enough to override everything else
|
||||
return 100;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,20 +2,61 @@
|
|||
# This is sourced by /usr/share/dump1090-fa/start-dump1090-fa as a
|
||||
# shellscript fragment.
|
||||
|
||||
# If you are using a PiAware sdcard image, this config file is regenerated
|
||||
# on boot based on the contents of piaware-config.txt; any changes made to this
|
||||
# file will be lost.
|
||||
|
||||
# dump1090-fa won't automatically start unless ENABLED=yes
|
||||
ENABLED=yes
|
||||
|
||||
RECEIVER_OPTIONS="--device-index 0 --gain -10 --ppm 0"
|
||||
DECODER_OPTIONS="--max-range 360 --fix"
|
||||
NET_OPTIONS="--net --net-heartbeat 60 --net-ro-size 1300 --net-ro-interval 0.2 --net-ri-port 0 --net-ro-port 30002 --net-sbs-port 30003 --net-bi-port 30004,30104 --net-bo-port 30005"
|
||||
JSON_OPTIONS="--json-location-accuracy 1"
|
||||
# SDR device type. Use "none" for a net-only configuration
|
||||
RECEIVER=rtlsdr
|
||||
# serial number or device index of device to use (only needed if there is more than one SDR connected)
|
||||
RECEIVER_SERIAL=
|
||||
# Initial receiver gain, in dB. If adaptive gain is enabled (see below) the actual gain
|
||||
# may change over time
|
||||
RECEIVER_GAIN=60
|
||||
|
||||
# Use a machine-specific wisdom file if it exists
|
||||
if [ -f /etc/dump1090-fa/wisdom.local ]
|
||||
then
|
||||
RECEIVER_OPTIONS="${RECEIVER_OPTIONS} --wisdom /etc/dump1090-fa/wisdom.local"
|
||||
fi
|
||||
# Adjust gain to try to achieve optimal dynamic range / noise floor?
|
||||
ADAPTIVE_DYNAMIC_RANGE=yes
|
||||
# Target dynamic range in dB (leave blank to autoselect based on SDR type)
|
||||
ADAPTIVE_DYNAMIC_RANGE_TARGET=
|
||||
# Reduce gain when loud message bursts from nearby aircraft are seen?
|
||||
ADAPTIVE_BURST=no
|
||||
# Gain range to allow when changing gain, in dB (empty = no limit)
|
||||
ADAPTIVE_MIN_GAIN=
|
||||
ADAPTIVE_MAX_GAIN=
|
||||
|
||||
# Turn on options to reduce load on slower CPUs, at the expense of slightly worse decoder performance.
|
||||
# Setting "auto" will enable these options only if the CPU appears to be a slow CPU (currently this
|
||||
# means armv6 only, e.g. Pi Zero)
|
||||
SLOW_CPU=auto
|
||||
# Local wisdom file used to select DSP implementations; uses built-in ranking if the file is missing
|
||||
WISDOM=/etc/dump1090-fa/wisdom.local
|
||||
|
||||
# Correct CRC errors where possible
|
||||
ERROR_CORRECTION=yes
|
||||
|
||||
# Receiver location, used for some types of position decoding. Provide the location as
|
||||
# signed decimal degrees. If not given here, dump1090 will also try to read a receiver
|
||||
# location from /var/cache/piaware/location.env (written automatically by PiAware, if installed)
|
||||
RECEIVER_LAT=
|
||||
RECEIVER_LON=
|
||||
# Maximum range, in NM. Positions more distant than this are ignored. No limit if not set.
|
||||
MAX_RANGE=360
|
||||
|
||||
# Network ports to listen on for connections
|
||||
NET_RAW_INPUT_PORTS=
|
||||
NET_RAW_OUTPUT_PORTS=30002
|
||||
NET_SBS_OUTPUT_PORTS=30003
|
||||
NET_BEAST_INPUT_PORTS=30004,30104
|
||||
NET_BEAST_OUTPUT_PORTS=30005
|
||||
|
||||
# Accuracy of location written to JSON output
|
||||
JSON_LOCATION_ACCURACY=1
|
||||
|
||||
# Additional options can be added here:
|
||||
EXTRA_OPTIONS=""
|
||||
|
||||
# If OVERRIDE_OPTIONS is set, only those options are used; all other options
|
||||
# in this config file are ignored.
|
||||
OVERRIDE_OPTIONS=""
|
||||
|
||||
# This is a marker to make it easier for scripts to identify a v6-style config file
|
||||
CONFIG_STYLE=6
|
||||
|
|
|
|||
|
|
@ -4,4 +4,6 @@ debian/lighttpd/* etc/lighttpd/conf-available
|
|||
bladerf/* usr/share/dump1090-fa/bladerf
|
||||
debian/start-dump1090-fa usr/share/dump1090-fa/
|
||||
debian/generate-wisdom usr/share/dump1090-fa/
|
||||
debian/upgrade-config usr/share/dump1090-fa/
|
||||
debian/dump1090-fa.default usr/share/dump1090-fa/
|
||||
starch-benchmark /usr/lib/dump1090-fa/
|
||||
|
|
|
|||
|
|
@ -63,6 +63,17 @@ case "$1" in
|
|||
fi
|
||||
fi
|
||||
|
||||
# on upgrade from pre-6.0, update the defaults file to the new syntax
|
||||
if dpkg --compare-versions "$2" lt-nl "6.0"
|
||||
then
|
||||
if [ -f /etc/default/dump1090-fa ]
|
||||
then
|
||||
echo "Trying to upgrade existing config to new syntax.." >&2
|
||||
/usr/share/dump1090-fa/upgrade-config /etc/default/dump1090-fa /usr/share/dump1090-fa/dump1090-fa.default \
|
||||
|| echo "Something went wrong upgrading the config; your config may be broken. Sorry!" >&1
|
||||
fi
|
||||
fi
|
||||
|
||||
if dpkg --compare-versions "$2" le "5.0"
|
||||
then
|
||||
echo "Enabling lighttpd skyaware module.." >&2
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ After=network.target
|
|||
User=dump1090
|
||||
RuntimeDirectory=dump1090-fa
|
||||
RuntimeDirectoryMode=0755
|
||||
ExecStart=/usr/share/dump1090-fa/start-dump1090-fa --write-json %t/dump1090-fa --quiet
|
||||
ExecStart=/usr/share/dump1090-fa/start-dump1090-fa --write-json %t/dump1090-fa
|
||||
SyslogIdentifier=dump1090-fa
|
||||
Type=simple
|
||||
Restart=on-failure
|
||||
|
|
|
|||
|
|
@ -15,19 +15,93 @@ then
|
|||
. /var/cache/piaware/location.env
|
||||
fi
|
||||
|
||||
if [ "x$ENABLED" != "xyes" ]
|
||||
if [ "$ENABLED" != "yes" ]
|
||||
then
|
||||
echo "dump1090-fa not enabled in /etc/default/dump1090-fa" >&2
|
||||
exit 64
|
||||
fi
|
||||
|
||||
if [ -n "$PIAWARE_LAT" -a -n "$PIAWARE_LON" ]
|
||||
# process options
|
||||
|
||||
# if there's no CONFIG_STYLE, infer a version
|
||||
if [ -z "$CONFIG_STYLE" ]
|
||||
then
|
||||
POSITION="--lat $PIAWARE_LAT --lon $PIAWARE_LON"
|
||||
if [ -n "$RECEIVER_OPTIONS" -o -n "$DECODER_OPTIONS" -o -n "$NET_OPTIONS" -o -n "$JSON_OPTIONS" ]
|
||||
then
|
||||
CONFIG_STYLE=5
|
||||
else
|
||||
CONFIG_STYLE=6
|
||||
fi
|
||||
fi
|
||||
|
||||
exec /usr/bin/dump1090-fa \
|
||||
$RECEIVER_OPTIONS $DECODER_OPTIONS $NET_OPTIONS $JSON_OPTIONS $POSITION \
|
||||
"$@"
|
||||
is_slow_cpu() {
|
||||
case "$SLOW_CPU" in
|
||||
yes) return 0 ;;
|
||||
auto)
|
||||
case $(uname -m) in
|
||||
armv6*) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
if [ "$CONFIG_STYLE" = "5" ]
|
||||
then
|
||||
# old style config file
|
||||
echo "/etc/default/dump1090-fa is using the old config style, please consider updating it" >&2
|
||||
OPTS="$RECEIVER_OPTIONS $DECODER_OPTIONS $NET_OPTIONS $JSON_OPTIONS"
|
||||
elif [ -n "$OVERRIDE_OPTIONS" ]
|
||||
then
|
||||
# ignore all other settings, use only provided options
|
||||
OPTS="$OVERRIDE_OPTIONS"
|
||||
else
|
||||
# build a list of options based on config settings
|
||||
OPTS=""
|
||||
|
||||
if [ "${RECEIVER:-none}" = "none" ]
|
||||
then
|
||||
OPTS="$OPTS --device-type none"
|
||||
else
|
||||
if [ -n "$RECEIVER" ]; then OPTS="$OPTS --device-type $RECEIVER"; fi
|
||||
if [ -n "$RECEIVER_SERIAL" ]; then OPTS="$OPTS --device-index $RECEIVER_SERIAL"; fi
|
||||
if [ -n "$RECEIVER_GAIN" ]; then OPTS="$OPTS --gain $RECEIVER_GAIN"; fi
|
||||
if [ -n "$WISDOM" -a -f "$WISDOM" ]; then OPTS="$OPTS --wisdom $WISDOM"; fi
|
||||
|
||||
if [ "$ADAPTIVE_DYNAMIC_RANGE" = "yes" ]; then OPTS="$OPTS --adaptive-range"; fi
|
||||
if [ -n "$ADAPTIVE_DYNAMIC_RANGE_TARGET" ]; then OPTS="$OPTS --adaptive-range-target $ADAPTIVE_DYNAMIC_RANGE_TARGET"; fi
|
||||
if [ "$ADAPTIVE_BURST" = "yes" ]; then OPTS="$OPTS --adaptive-burst"; fi
|
||||
if [ -n "$ADAPTIVE_MIN_GAIN" ]; then OPTS="$OPTS --adaptive-min-gain $ADAPTIVE_MIN_GAIN"; fi
|
||||
if [ -n "$ADAPTIVE_MAX_GAIN" ]; then OPTS="$OPTS --adaptive-max-gain $ADAPTIVE_MAX_GAIN"; fi
|
||||
|
||||
if is_slow_cpu
|
||||
then
|
||||
OPTS="$OPTS --adaptive-duty-cycle 10 --no-fix-df"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$ERROR_CORRECTION" = "yes" ]; then OPTS="$OPTS --fix"; fi
|
||||
|
||||
if [ -n "$RECEIVER_LAT" -a -n "$RECEIVER_LON" ]; then
|
||||
OPTS="$OPTS --lat $RECEIVER_LAT --lon $RECEIVER_LON"
|
||||
elif [ -n "$PIAWARE_LAT" -a -n "$PIAWARE_LON" ]; then
|
||||
OPTS="$OPTS --lat $PIAWARE_LAT --lon $PIAWARE_LON"
|
||||
fi
|
||||
|
||||
if [ -n "$MAX_RANGE" ]; then OPTS="$OPTS --max-range $MAX_RANGE"; fi
|
||||
|
||||
if [ -n "$NET_RAW_INPUT_PORTS" ]; then OPTS="$OPTS --net-ri-port $NET_RAW_INPUT_PORTS"; fi
|
||||
if [ -n "$NET_RAW_OUTPUT_PORTS" ]; then OPTS="$OPTS --net-ro-port $NET_RAW_OUTPUT_PORTS"; fi
|
||||
if [ -n "$NET_SBS_OUTPUT_PORTS" ]; then OPTS="$OPTS --net-sbs-port $NET_SBS_OUTPUT_PORTS"; fi
|
||||
if [ -n "$NET_BEAST_INPUT_PORTS" ]; then OPTS="$OPTS --net-bi-port $NET_BEAST_INPUT_PORTS"; fi
|
||||
if [ -n "$NET_BEAST_OUTPUT_PORTS" ]; then OPTS="$OPTS --net-bo-port $NET_BEAST_OUTPUT_PORTS"; fi
|
||||
|
||||
if [ -n "$JSON_LOCATION_ACCURACY" ]; then OPTS="$OPTS --json-location-accuracy $JSON_LOCATION_ACCURACY"; fi
|
||||
|
||||
if [ -n "$EXTRA_OPTIONS" ]; then OPTS="$OPTS $EXTRA_OPTIONS"; fi
|
||||
fi
|
||||
|
||||
exec /usr/bin/dump1090-fa --quiet $OPTS "$@"
|
||||
# exec failed, do not restart
|
||||
exit 64
|
||||
|
|
|
|||
|
|
@ -0,0 +1,178 @@
|
|||
#!/bin/sh
|
||||
|
||||
# This script runs during upgrade from pre-6.0 to try to
|
||||
# update /etc/default/dump1090-fa to the new-style
|
||||
# config.
|
||||
|
||||
if [ $# -lt 2 ]
|
||||
then
|
||||
echo "syntax: $0 path-to-config path-to-package-defaults" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
OLDCONFIG="$1"
|
||||
NEWCONFIG="${OLDCONFIG}.v6-upgrade"
|
||||
BACKUPCONFIG="${OLDCONFIG}.pre-v6-upgrade"
|
||||
PACKAGECONFIG="$2"
|
||||
|
||||
if [ ! -f $OLDCONFIG ]
|
||||
then
|
||||
echo "$OLDCONFIG does not exist, nothing to upgrade" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ ! -f $PACKAGECONFIG ]
|
||||
then
|
||||
echo "$PACKAGECONFIG does not exist, cannot continue" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -f $BACKUPCONFIG ]
|
||||
then
|
||||
echo "$BACKUPCONFIG already exists, I'm not going to clobber it" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# set some assumed defaults (5.0 dump1090 binary defaults if no command-line options are given)
|
||||
ENABLED="no"
|
||||
RECEIVER="rtlsdr"
|
||||
RECEIVER_SERIAL=""
|
||||
RECEIVER_GAIN="50"
|
||||
WISDOM=""
|
||||
ERROR_CORRECTION="no"
|
||||
MAX_RANGE=""
|
||||
NET_RAW_INPUT_PORTS="30001"
|
||||
NET_RAW_OUTPUT_PORTS="30002"
|
||||
NET_SBS_OUTPUT_PORTS="30003"
|
||||
NET_BEAST_INPUT_PORTS="30004,30104"
|
||||
NET_BEAST_OUTPUT_PORTS="30005"
|
||||
EXTRAS_NET_RO_SIZE="0"
|
||||
EXTRAS_NET_RO_INTERVAL="0"
|
||||
EXTRAS_NET_HEARTBEAT="60"
|
||||
|
||||
# read the old config
|
||||
. "$OLDCONFIG"
|
||||
|
||||
# if there's no CONFIG_STYLE, infer a version
|
||||
if [ -z "$CONFIG_STYLE" ]
|
||||
then
|
||||
if [ -n "$RECEIVER_OPTIONS" -o -n "$DECODER_OPTIONS" -o -n "$NET_OPTIONS" -o -n "$JSON_OPTIONS" ]
|
||||
then
|
||||
CONFIG_STYLE=5
|
||||
else
|
||||
CONFIG_STYLE=6
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$CONFIG_STYLE" = "6" ]
|
||||
then
|
||||
echo "$OLDCONFIG seems to already be a new-style config, nothing to upgrade" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# process all the options from the old config file and accumulate settings in env vars
|
||||
process_options() {
|
||||
while [ $# -gt 0 ]
|
||||
do
|
||||
opt="$1"
|
||||
shift
|
||||
case "$opt" in
|
||||
--device-type) RECEIVER="$1"; shift ;;
|
||||
--device-index) RECEIVER_SERIAL="$1"; shift ;;
|
||||
--gain) RECEIVER_GAIN="$1"; shift ;;
|
||||
--max-range) MAX_RANGE="$1"; shift ;;
|
||||
--fix) ERROR_CORRECTION="yes" ;;
|
||||
--net) ;;
|
||||
--net-ri-port) NET_RAW_INPUT_PORTS="$1"; shift ;;
|
||||
--net-ro-port) NET_RAW_OUTPUT_PORTS="$1"; shift ;;
|
||||
--net-sbs-port) NET_SBS_OUTPUT_PORTS="$1"; shift ;;
|
||||
--net-bi-port) NET_BEAST_INPUT_PORTS="$1"; shift ;;
|
||||
--net-bo-port) NET_BEAST_OUTPUT_PORTS="$1"; shift ;;
|
||||
--json-location-accuracy) JSON_LOCATION_ACCURACY="$1"; shift ;;
|
||||
--wisdom) WISDOM="$1"; shift ;;
|
||||
|
||||
--ppm) EXTRAS_PPM="$1"; shift ;;
|
||||
--net-heartbeat) EXTRAS_NET_HEARTBEAT="$1"; shift ;;
|
||||
--net-ro-size) EXTRAS_NET_RO_SIZE="$1"; shift ;;
|
||||
--net-ro-interval) EXTRAS_NET_RO_INTERVAL="$1"; shift ;;
|
||||
|
||||
*) EXTRA_OPTIONS="$EXTRA_OPTIONS ${opt}" ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
process_options $RECEIVER_OPTIONS $DECODER_OPTIONS $NET_OPTIONS $JSON_OPTIONS
|
||||
|
||||
# update EXTRA_OPTIONS for any non-default special settings
|
||||
if [ "${EXTRAS_PPM:-0}" != "0" ]; then EXTRA_OPTIONS="$EXTRA_OPTIONS --ppm $EXTRAS_PPM"; fi
|
||||
if [ "${EXTRAS_NET_HEARTBEAT:-60}" != "60" ]; then EXTRA_OPTIONS="$EXTRA_OPTIONS --net-heartbeat $EXTRAS_NET_HEARTBEAT"; fi
|
||||
if [ "${EXTRAS_NET_RO_SIZE:-1300}" != "1300" ]; then EXTRA_OPTIONS="$EXTRA_OPTIONS --net-ro-size $EXTRAS_NET_RO_SIZE"; fi
|
||||
if [ "${EXTRAS_NET_RO_INTERVAL:-1300}" != "0.2" ]; then EXTRA_OPTIONS="$EXTRA_OPTIONS --net-ro-interval $EXTRAS_NET_RO_INTERVAL"; fi
|
||||
|
||||
# special case for device index 0 (the default)
|
||||
if [ "${RECEIVER_SERIAL}" = "0" ]; then RECEIVER_SERIAL=""; fi
|
||||
|
||||
# special case for gain -10 -> gain 60
|
||||
if [ "${RECEIVER_GAIN}" = "-10" ]; then RECEIVER_GAIN="60"; fi
|
||||
|
||||
# special case for ports set to zero (new config uses a blank entry for that)
|
||||
if [ "${NET_RAW_INPUT_PORTS}" = "0" ]; then NET_RAW_INPUT_PORTS=""; fi
|
||||
if [ "${NET_RAW_OUTPUT_PORTS}" = "0" ]; then NET_RAW_OUTPUT_PORTS=""; fi
|
||||
if [ "${NET_SBS_INPUT_PORTS}" = "0" ]; then NET_SBS_OUTPUT_PORTS=""; fi
|
||||
if [ "${NET_BEAST_INPUT_PORTS}" = "0" ]; then NET_BEAST_INPUT_PORTS=""; fi
|
||||
if [ "${NET_BEAST_OUTPUT_PORTS}" = "0" ]; then NET_BEAST_OUTPUT_PORTS=""; fi
|
||||
|
||||
SEDSCRIPT=$(mktemp -t dump1090XXX.sed)
|
||||
|
||||
# set up the sedscript
|
||||
# nb: all values either derived from env vars or the package defaults,
|
||||
# except for adaptive gain settings which we default to off on upgraded
|
||||
# installs. New installs using the package defaults will default to on.
|
||||
cat >>$SEDSCRIPT <<EOF
|
||||
s@^ENABLED=.*@ENABLED=${ENABLED}@
|
||||
s@^RECEIVER=.*@RECEIVER=${RECEIVER}@
|
||||
s@^RECEIVER_SERIAL=.*@RECEIVER_SERIAL="${RECEIVER_SERIAL}"@
|
||||
s@^RECEIVER_GAIN=.*@RECEIVER_GAIN=${RECEIVER_GAIN}@
|
||||
s@^WISDOM=.*@WISDOM=${WISDOM}@
|
||||
s@^ERROR_CORRECTION=.*@ERROR_CORRECTION=${ERROR_CORRECTION}@
|
||||
s@^MAX_RANGE=.*@MAX_RANGE=${MAX_RANGE}@
|
||||
s@^NET_RAW_INPUT_PORTS=.*@NET_RAW_INPUT_PORTS=${NET_RAW_INPUT_PORTS}@
|
||||
s@^NET_RAW_OUTPUT_PORTS=.*@NET_RAW_OUTPUT_PORTS=${NET_RAW_OUTPUT_PORTS}@
|
||||
s@^NET_SBS_OUTPUT_PORTS=.*@NET_SBS_OUTPUT_PORTS=${NET_SBS_OUTPUT_PORTS}@
|
||||
s@^NET_BEAST_INPUT_PORTS=.*@NET_BEAST_INPUT_PORTS=${NET_BEAST_INPUT_PORTS}@
|
||||
s@^NET_BEAST_OUTPUT_PORTS=.*@NET_BEAST_OUTPUT_PORTS=${NET_BEAST_OUTPUT_PORTS}@
|
||||
s@^JSON_LOCATION_ACCURACY=.*@JSON_LOCATION_ACCURACY=${JSON_LOCATION_ACCURACY}@
|
||||
s@^EXTRA_OPTIONS=.*@EXTRA_OPTIONS="$EXTRA_OPTIONS"@
|
||||
s@^ADAPTIVE_DYNAMIC_RANGE=.*@ADAPTIVE_DYNAMIC_RANGE=no@
|
||||
s@^ADAPTIVE_BURST=.*@ADAPTIVE_BURST=no@
|
||||
EOF
|
||||
|
||||
# substitute into the standard config file to generate our customized config
|
||||
if ! sed -f $SEDSCRIPT <$PACKAGECONFIG >$NEWCONFIG
|
||||
then
|
||||
echo "Something went wrong trying to upgrade $OLDCONFIG, giving up.." >&2
|
||||
exit 1
|
||||
fi
|
||||
rm $SEDSCRIPT
|
||||
|
||||
# back up the old config and install the new config
|
||||
if ! cp -p $OLDCONFIG $BACKUPCONFIG
|
||||
then
|
||||
echo "Something went wrong trying to back up $OLDCONFIG, giving up.." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! mv $NEWCONFIG $OLDCONFIG
|
||||
then
|
||||
echo "Something went wrong trying to install the new version of $NEWCONFIG, giving up.." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# all good
|
||||
cat >&2 <<EOF
|
||||
Upgraded existing config $OLDCONFIG to the new config syntax.
|
||||
Please doublecheck that it looks ok!
|
||||
The old config file has been preserved at $BACKUPCONFIG
|
||||
EOF
|
||||
|
||||
exit 0
|
||||
|
|
@ -12,6 +12,16 @@
|
|||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
//On Windows platform, separate functions for allocating and freeing aligned memory must be used
|
||||
#ifdef _WIN32
|
||||
# include <malloc.h>
|
||||
# define util_aligned_alloc(alignment,size) (_aligned_malloc(size, alignment))
|
||||
# define util_aligned_free(ptr) (_aligned_free(ptr))
|
||||
#else
|
||||
# define util_aligned_alloc(alignment,size) (aligned_alloc(alignment,size))
|
||||
# define util_aligned_free(ptr) (free(ptr))
|
||||
#endif
|
||||
|
||||
#include "starch.h"
|
||||
|
||||
typedef struct timespec starch_benchmark_time;
|
||||
|
|
@ -76,7 +86,7 @@ void *starch_benchmark_aligned_alloc(size_t alignment, size_t type_alignment, si
|
|||
* of a more restrictive larger alignment)
|
||||
*/
|
||||
size_t header_size = (use_alignment < sizeof(void*) ? sizeof(void*) : use_alignment);
|
||||
char *block_ptr = aligned_alloc(use_alignment, header_size + size + use_alignment);
|
||||
char *block_ptr = util_aligned_alloc(use_alignment, header_size + size + use_alignment);
|
||||
if (!block_ptr) {
|
||||
fprintf(stderr, "STARCH_BENCHMARK_ALLOC of %zu bytes failed: %s\n", size, strerror(errno));
|
||||
return NULL;
|
||||
|
|
@ -99,7 +109,7 @@ void starch_benchmark_aligned_free(void *user_ptr)
|
|||
if (!user_ptr)
|
||||
return;
|
||||
void **stash = (void**)user_ptr - 1;
|
||||
free(*stash);
|
||||
util_aligned_free(*stash);
|
||||
}
|
||||
|
||||
static bool starch_benchmark_flavor_in_list(const char *flavor, const starch_benchmark_flavor_list *list)
|
||||
|
|
|
|||
|
|
@ -18,22 +18,27 @@
|
|||
# $(STARCH_BENCHMARK_OBJ): object files providing a standalone benchmarking app (link all of $(STARCH_OBJS) too)
|
||||
# explicit build rules for each object file listed in $(STARCH_OBJS)
|
||||
|
||||
MKDIR_P = mkdir -p
|
||||
STARCH_CFLAGS := -DSTARCH_MIX_AARCH64
|
||||
|
||||
|
||||
dsp/generated/flavor.armv8_neon_simd.o: dsp/generated/flavor.armv8_neon_simd.c dsp/impl/mean_power_u16.c dsp/impl/magnitude_power_uc8.c dsp/impl/magnitude_uc8.c dsp/impl/magnitude_sc16q11.c dsp/impl/count_above_u16.c dsp/impl/magnitude_sc16.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) -march=armv8-a+simd -ffast-math dsp/generated/flavor.armv8_neon_simd.c -o dsp/generated/flavor.armv8_neon_simd.o
|
||||
@$(MKDIR_P) $(dir $(STARCH_OBJ_PATH)dsp/generated/flavor.armv8_neon_simd.o)
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) -march=armv8-a+simd -ffast-math dsp/generated/flavor.armv8_neon_simd.c -o $(STARCH_OBJ_PATH)dsp/generated/flavor.armv8_neon_simd.o
|
||||
|
||||
dsp/generated/flavor.generic.o: dsp/generated/flavor.generic.c dsp/impl/mean_power_u16.c dsp/impl/magnitude_power_uc8.c dsp/impl/magnitude_uc8.c dsp/impl/magnitude_sc16q11.c dsp/impl/count_above_u16.c dsp/impl/magnitude_sc16.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/flavor.generic.c -o dsp/generated/flavor.generic.o
|
||||
@$(MKDIR_P) $(dir $(STARCH_OBJ_PATH)dsp/generated/flavor.generic.o)
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/flavor.generic.c -o $(STARCH_OBJ_PATH)dsp/generated/flavor.generic.o
|
||||
|
||||
dsp/generated/dispatcher.o: dsp/generated/dispatcher.c dsp/impl/mean_power_u16.c dsp/impl/magnitude_power_uc8.c dsp/impl/magnitude_uc8.c dsp/impl/magnitude_sc16q11.c dsp/impl/count_above_u16.c dsp/impl/magnitude_sc16.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/dispatcher.c -o dsp/generated/dispatcher.o
|
||||
@$(MKDIR_P) $(dir $(STARCH_OBJ_PATH)dsp/generated/dispatcher.o)
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/dispatcher.c -o $(STARCH_OBJ_PATH)dsp/generated/dispatcher.o
|
||||
|
||||
STARCH_OBJS := dsp/generated/flavor.armv8_neon_simd.o dsp/generated/flavor.generic.o dsp/generated/dispatcher.o
|
||||
|
||||
|
||||
dsp/generated/benchmark.o: dsp/generated/benchmark.c dsp/benchmark/magnitude_sc16_benchmark.c dsp/benchmark/magnitude_uc8_benchmark.c dsp/benchmark/magnitude_power_uc8_benchmark.c dsp/benchmark/mean_power_u16_benchmark.c dsp/benchmark/count_above_u16_benchmark.c dsp/benchmark/magnitude_sc16q11_benchmark.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/benchmark.c -o dsp/generated/benchmark.o
|
||||
@$(MKDIR_P) $(dir $(STARCH_OBJ_PATH)dsp/generated/benchmark.o)
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/benchmark.c -o $(STARCH_OBJ_PATH)dsp/generated/benchmark.o
|
||||
|
||||
STARCH_BENCHMARK_OBJ := dsp/generated/benchmark.o
|
||||
|
|
|
|||
|
|
@ -18,22 +18,27 @@
|
|||
# $(STARCH_BENCHMARK_OBJ): object files providing a standalone benchmarking app (link all of $(STARCH_OBJS) too)
|
||||
# explicit build rules for each object file listed in $(STARCH_OBJS)
|
||||
|
||||
MKDIR_P = mkdir -p
|
||||
STARCH_CFLAGS := -DSTARCH_MIX_ARM
|
||||
|
||||
|
||||
dsp/generated/flavor.armv7a_neon_vfpv4.o: dsp/generated/flavor.armv7a_neon_vfpv4.c dsp/impl/mean_power_u16.c dsp/impl/magnitude_power_uc8.c dsp/impl/magnitude_uc8.c dsp/impl/magnitude_sc16q11.c dsp/impl/count_above_u16.c dsp/impl/magnitude_sc16.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) -march=armv7-a+neon-vfpv4 -mfpu=neon-vfpv4 -ffast-math dsp/generated/flavor.armv7a_neon_vfpv4.c -o dsp/generated/flavor.armv7a_neon_vfpv4.o
|
||||
@$(MKDIR_P) $(dir $(STARCH_OBJ_PATH)dsp/generated/flavor.armv7a_neon_vfpv4.o)
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) -march=armv7-a+neon-vfpv4 -mfpu=neon-vfpv4 -ffast-math dsp/generated/flavor.armv7a_neon_vfpv4.c -o $(STARCH_OBJ_PATH)dsp/generated/flavor.armv7a_neon_vfpv4.o
|
||||
|
||||
dsp/generated/flavor.generic.o: dsp/generated/flavor.generic.c dsp/impl/mean_power_u16.c dsp/impl/magnitude_power_uc8.c dsp/impl/magnitude_uc8.c dsp/impl/magnitude_sc16q11.c dsp/impl/count_above_u16.c dsp/impl/magnitude_sc16.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/flavor.generic.c -o dsp/generated/flavor.generic.o
|
||||
@$(MKDIR_P) $(dir $(STARCH_OBJ_PATH)dsp/generated/flavor.generic.o)
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/flavor.generic.c -o $(STARCH_OBJ_PATH)dsp/generated/flavor.generic.o
|
||||
|
||||
dsp/generated/dispatcher.o: dsp/generated/dispatcher.c dsp/impl/mean_power_u16.c dsp/impl/magnitude_power_uc8.c dsp/impl/magnitude_uc8.c dsp/impl/magnitude_sc16q11.c dsp/impl/count_above_u16.c dsp/impl/magnitude_sc16.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/dispatcher.c -o dsp/generated/dispatcher.o
|
||||
@$(MKDIR_P) $(dir $(STARCH_OBJ_PATH)dsp/generated/dispatcher.o)
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/dispatcher.c -o $(STARCH_OBJ_PATH)dsp/generated/dispatcher.o
|
||||
|
||||
STARCH_OBJS := dsp/generated/flavor.armv7a_neon_vfpv4.o dsp/generated/flavor.generic.o dsp/generated/dispatcher.o
|
||||
|
||||
|
||||
dsp/generated/benchmark.o: dsp/generated/benchmark.c dsp/benchmark/magnitude_sc16_benchmark.c dsp/benchmark/magnitude_uc8_benchmark.c dsp/benchmark/magnitude_power_uc8_benchmark.c dsp/benchmark/mean_power_u16_benchmark.c dsp/benchmark/count_above_u16_benchmark.c dsp/benchmark/magnitude_sc16q11_benchmark.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/benchmark.c -o dsp/generated/benchmark.o
|
||||
@$(MKDIR_P) $(dir $(STARCH_OBJ_PATH)dsp/generated/benchmark.o)
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/benchmark.c -o $(STARCH_OBJ_PATH)dsp/generated/benchmark.o
|
||||
|
||||
STARCH_BENCHMARK_OBJ := dsp/generated/benchmark.o
|
||||
|
|
|
|||
|
|
@ -18,19 +18,23 @@
|
|||
# $(STARCH_BENCHMARK_OBJ): object files providing a standalone benchmarking app (link all of $(STARCH_OBJS) too)
|
||||
# explicit build rules for each object file listed in $(STARCH_OBJS)
|
||||
|
||||
MKDIR_P = mkdir -p
|
||||
STARCH_CFLAGS := -DSTARCH_MIX_GENERIC
|
||||
|
||||
|
||||
dsp/generated/flavor.generic.o: dsp/generated/flavor.generic.c dsp/impl/mean_power_u16.c dsp/impl/magnitude_power_uc8.c dsp/impl/magnitude_uc8.c dsp/impl/magnitude_sc16q11.c dsp/impl/count_above_u16.c dsp/impl/magnitude_sc16.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/flavor.generic.c -o dsp/generated/flavor.generic.o
|
||||
@$(MKDIR_P) $(dir $(STARCH_OBJ_PATH)dsp/generated/flavor.generic.o)
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/flavor.generic.c -o $(STARCH_OBJ_PATH)dsp/generated/flavor.generic.o
|
||||
|
||||
dsp/generated/dispatcher.o: dsp/generated/dispatcher.c dsp/impl/mean_power_u16.c dsp/impl/magnitude_power_uc8.c dsp/impl/magnitude_uc8.c dsp/impl/magnitude_sc16q11.c dsp/impl/count_above_u16.c dsp/impl/magnitude_sc16.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/dispatcher.c -o dsp/generated/dispatcher.o
|
||||
@$(MKDIR_P) $(dir $(STARCH_OBJ_PATH)dsp/generated/dispatcher.o)
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/dispatcher.c -o $(STARCH_OBJ_PATH)dsp/generated/dispatcher.o
|
||||
|
||||
STARCH_OBJS := dsp/generated/flavor.generic.o dsp/generated/dispatcher.o
|
||||
|
||||
|
||||
dsp/generated/benchmark.o: dsp/generated/benchmark.c dsp/benchmark/magnitude_sc16_benchmark.c dsp/benchmark/magnitude_uc8_benchmark.c dsp/benchmark/magnitude_power_uc8_benchmark.c dsp/benchmark/mean_power_u16_benchmark.c dsp/benchmark/count_above_u16_benchmark.c dsp/benchmark/magnitude_sc16q11_benchmark.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/benchmark.c -o dsp/generated/benchmark.o
|
||||
@$(MKDIR_P) $(dir $(STARCH_OBJ_PATH)dsp/generated/benchmark.o)
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/benchmark.c -o $(STARCH_OBJ_PATH)dsp/generated/benchmark.o
|
||||
|
||||
STARCH_BENCHMARK_OBJ := dsp/generated/benchmark.o
|
||||
|
|
|
|||
|
|
@ -18,22 +18,27 @@
|
|||
# $(STARCH_BENCHMARK_OBJ): object files providing a standalone benchmarking app (link all of $(STARCH_OBJS) too)
|
||||
# explicit build rules for each object file listed in $(STARCH_OBJS)
|
||||
|
||||
MKDIR_P = mkdir -p
|
||||
STARCH_CFLAGS := -DSTARCH_MIX_X86
|
||||
|
||||
|
||||
dsp/generated/flavor.x86_avx2.o: dsp/generated/flavor.x86_avx2.c dsp/impl/mean_power_u16.c dsp/impl/magnitude_power_uc8.c dsp/impl/magnitude_uc8.c dsp/impl/magnitude_sc16q11.c dsp/impl/count_above_u16.c dsp/impl/magnitude_sc16.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) -mavx2 -ffast-math dsp/generated/flavor.x86_avx2.c -o dsp/generated/flavor.x86_avx2.o
|
||||
@$(MKDIR_P) $(dir $(STARCH_OBJ_PATH)dsp/generated/flavor.x86_avx2.o)
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) -mavx2 -ffast-math dsp/generated/flavor.x86_avx2.c -o $(STARCH_OBJ_PATH)dsp/generated/flavor.x86_avx2.o
|
||||
|
||||
dsp/generated/flavor.generic.o: dsp/generated/flavor.generic.c dsp/impl/mean_power_u16.c dsp/impl/magnitude_power_uc8.c dsp/impl/magnitude_uc8.c dsp/impl/magnitude_sc16q11.c dsp/impl/count_above_u16.c dsp/impl/magnitude_sc16.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/flavor.generic.c -o dsp/generated/flavor.generic.o
|
||||
@$(MKDIR_P) $(dir $(STARCH_OBJ_PATH)dsp/generated/flavor.generic.o)
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/flavor.generic.c -o $(STARCH_OBJ_PATH)dsp/generated/flavor.generic.o
|
||||
|
||||
dsp/generated/dispatcher.o: dsp/generated/dispatcher.c dsp/impl/mean_power_u16.c dsp/impl/magnitude_power_uc8.c dsp/impl/magnitude_uc8.c dsp/impl/magnitude_sc16q11.c dsp/impl/count_above_u16.c dsp/impl/magnitude_sc16.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/dispatcher.c -o dsp/generated/dispatcher.o
|
||||
@$(MKDIR_P) $(dir $(STARCH_OBJ_PATH)dsp/generated/dispatcher.o)
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/dispatcher.c -o $(STARCH_OBJ_PATH)dsp/generated/dispatcher.o
|
||||
|
||||
STARCH_OBJS := dsp/generated/flavor.x86_avx2.o dsp/generated/flavor.generic.o dsp/generated/dispatcher.o
|
||||
|
||||
|
||||
dsp/generated/benchmark.o: dsp/generated/benchmark.c dsp/benchmark/magnitude_sc16_benchmark.c dsp/benchmark/magnitude_uc8_benchmark.c dsp/benchmark/magnitude_power_uc8_benchmark.c dsp/benchmark/mean_power_u16_benchmark.c dsp/benchmark/count_above_u16_benchmark.c dsp/benchmark/magnitude_sc16q11_benchmark.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/benchmark.c -o dsp/generated/benchmark.o
|
||||
@$(MKDIR_P) $(dir $(STARCH_OBJ_PATH)dsp/generated/benchmark.o)
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/benchmark.c -o $(STARCH_OBJ_PATH)dsp/generated/benchmark.o
|
||||
|
||||
STARCH_BENCHMARK_OBJ := dsp/generated/benchmark.o
|
||||
|
|
|
|||
18
dump1090.c
18
dump1090.c
|
|
@ -110,11 +110,10 @@ static void modesInitConfig(void) {
|
|||
memset(&Modes, 0, sizeof(Modes));
|
||||
|
||||
// Now initialise things that should not be 0/NULL to their defaults
|
||||
Modes.gain = MODES_MAX_GAIN;
|
||||
Modes.gain = MODES_DEFAULT_GAIN;
|
||||
Modes.freq = MODES_DEFAULT_FREQ;
|
||||
Modes.check_crc = 1;
|
||||
Modes.fix_df = 1;
|
||||
Modes.net_heartbeat_interval = MODES_NET_HEARTBEAT_INTERVAL;
|
||||
Modes.interactive_display_ttl = MODES_INTERACTIVE_DISPLAY_TTL;
|
||||
Modes.json_interval = 1000;
|
||||
Modes.json_stats_interval = 60000;
|
||||
|
|
@ -122,10 +121,16 @@ static void modesInitConfig(void) {
|
|||
Modes.maxRange = 1852 * 300; // 300NM default max range
|
||||
Modes.mode_ac_auto = 1;
|
||||
|
||||
Modes.net_heartbeat_interval = MODES_NET_HEARTBEAT_INTERVAL;
|
||||
Modes.net_output_flush_size = 1300;
|
||||
Modes.net_output_flush_interval = 500;
|
||||
|
||||
// adaptive
|
||||
Modes.adaptive_min_gain_db = 0;
|
||||
Modes.adaptive_max_gain_db = 99999;
|
||||
|
||||
Modes.adaptive_duty_cycle = 0.5;
|
||||
|
||||
Modes.adaptive_burst_control = false;
|
||||
Modes.adaptive_burst_alpha = 2.0 / (5 + 1);
|
||||
Modes.adaptive_burst_change_delay = 5;
|
||||
|
|
@ -138,7 +143,7 @@ static void modesInitConfig(void) {
|
|||
Modes.adaptive_range_alpha = 2.0 / (5 + 1);
|
||||
Modes.adaptive_range_percentile = 40;
|
||||
Modes.adaptive_range_change_delay = 10;
|
||||
Modes.adaptive_range_rescan_delay = 900;
|
||||
Modes.adaptive_range_rescan_delay = 3600;
|
||||
|
||||
sdrInitConfig();
|
||||
}
|
||||
|
|
@ -335,7 +340,7 @@ static void showHelp(void)
|
|||
" Decoder settings\n"
|
||||
"\n"
|
||||
// ------ 80 char limit ----------------------------------------------------------|
|
||||
"--gain <db> Set gain (default: max gain. Use -10 for auto-gain)\n"
|
||||
"--gain <db> Set gain in dB (default: varies by SDR type)\n"
|
||||
"--freq <hz> Set frequency (default: 1090 Mhz)\n"
|
||||
"--fix Enable single-bit error correction using CRC\n"
|
||||
"--fix-2bit Enable two-bit error correction using CRC\n"
|
||||
|
|
@ -353,7 +358,7 @@ static void showHelp(void)
|
|||
" Adaptive gain\n"
|
||||
"\n"
|
||||
"--adaptive-burst Adjust gain for too-loud message bursts\n"
|
||||
"--adaptive-range-change-delay <s> Set delay after changing gain before\n"
|
||||
"--adaptive-burst-change-delay <s> Set delay after changing gain before\n"
|
||||
" resuming burst control (seconds)\n"
|
||||
"--adaptive-burst-alpha <a> Set burst rate smoothing factor\n"
|
||||
" (0..1, smaller=more smoothing)\n"
|
||||
|
|
@ -372,6 +377,7 @@ static void showHelp(void)
|
|||
" gain scanning (seconds)\n"
|
||||
"--adaptive-min-gain <g> Set gain adjustment range lower limit (dB)\n"
|
||||
"--adaptive-max-gain <g> Set gain adjustment range upper limit (dB)\n"
|
||||
"--adaptive-duty-cycle <p> Set adaptive gain duty cycle %% (1..100)\n"
|
||||
"\n"
|
||||
// ------ 80 char limit ----------------------------------------------------------|
|
||||
" Network connections\n"
|
||||
|
|
@ -764,6 +770,8 @@ int main(int argc, char **argv) {
|
|||
Modes.adaptive_min_gain_db = atof(argv[++j]);
|
||||
} else if (!strcmp(argv[j], "--adaptive-max-gain") && more) {
|
||||
Modes.adaptive_max_gain_db = atof(argv[++j]);
|
||||
} else if (!strcmp(argv[j], "--adaptive-duty-cycle") && more) {
|
||||
Modes.adaptive_duty_cycle = atof(argv[++j]) / 100.0;
|
||||
} else if (!strcmp(argv[j], "--adaptive-burst")) {
|
||||
Modes.adaptive_burst_control = true;
|
||||
} else if (!strcmp(argv[j], "--adaptive-burst-alpha") && more) {
|
||||
|
|
|
|||
46
dump1090.h
46
dump1090.h
|
|
@ -92,8 +92,8 @@
|
|||
#define MODES_RTL_BUF_SIZE (16*16384) // 256k
|
||||
#define MODES_MAG_BUF_SAMPLES (MODES_RTL_BUF_SIZE / 2) // Each sample is 2 bytes
|
||||
#define MODES_MAG_BUFFERS 12 // Number of magnitude buffers (should be smaller than RTL_BUFFERS for flowcontrol to work)
|
||||
#define MODES_AUTO_GAIN -10 // Use automatic gain
|
||||
#define MODES_MAX_GAIN 999999 // Use max available gain
|
||||
#define MODES_LEGACY_AUTO_GAIN -10 // old gain value for "use automatic gain"
|
||||
#define MODES_DEFAULT_GAIN 999999 // Use default SDR gain
|
||||
#define MODES_MSG_SQUELCH_DB 4.0 // Minimum SNR, in dB
|
||||
#define MODES_MSG_ENCODER_ERRS 3 // Maximum number of encoding errors
|
||||
|
||||
|
|
@ -202,6 +202,7 @@ typedef enum {
|
|||
typedef enum {
|
||||
COMMB_UNKNOWN,
|
||||
COMMB_AMBIGUOUS,
|
||||
COMMB_NOT_DECODED,
|
||||
COMMB_EMPTY_RESPONSE,
|
||||
COMMB_DATALINK_CAPS,
|
||||
COMMB_GICB_CAPS,
|
||||
|
|
@ -209,7 +210,9 @@ typedef enum {
|
|||
COMMB_ACAS_RA,
|
||||
COMMB_VERTICAL_INTENT,
|
||||
COMMB_TRACK_TURN,
|
||||
COMMB_HEADING_SPEED
|
||||
COMMB_HEADING_SPEED,
|
||||
COMMB_MRAR,
|
||||
COMMB_AIRBORNE_POSITION
|
||||
} commb_format_t;
|
||||
|
||||
typedef enum {
|
||||
|
|
@ -237,6 +240,24 @@ typedef enum {
|
|||
NAV_ALT_INVALID, NAV_ALT_UNKNOWN, NAV_ALT_AIRCRAFT, NAV_ALT_MCP, NAV_ALT_FMS
|
||||
} nav_altitude_source_t;
|
||||
|
||||
// BDS4,4 MRAR - FOM/Source values
|
||||
typedef enum {
|
||||
MRAR_SOURCE_INVALID = 0,
|
||||
MRAR_SOURCE_INS = 1,
|
||||
MRAR_SOURCE_GNSS = 2,
|
||||
MRAR_SOURCE_DMEDME = 3,
|
||||
MRAR_SOURCE_VORDME = 4,
|
||||
MRAR_SOURCE_RESERVED = 5
|
||||
} mrar_source_t;
|
||||
|
||||
// BDS4,4 and BDS4,5 hazard reports
|
||||
typedef enum {
|
||||
HAZARD_NIL = 0,
|
||||
HAZARD_LIGHT = 1,
|
||||
HAZARD_MODERATE = 2,
|
||||
HAZARD_SEVERE = 3
|
||||
} hazard_t;
|
||||
|
||||
#define MODES_NON_ICAO_ADDRESS (1<<24) // Set on addresses to indicate they are not ICAO addresses
|
||||
|
||||
#define MODES_INTERACTIVE_REFRESH_TIME 250 // Milliseconds
|
||||
|
|
@ -364,6 +385,7 @@ struct _Modes { // Internal state
|
|||
uint64_t json_stats_interval; // Interval between rewriting the json stats file, in milliseconds
|
||||
int json_location_accuracy; // Accuracy of location metadata: 0=none, 1=approx, 2=exact
|
||||
double faup_rate_multiplier; // Multiplier to adjust rate of faup1090 messages emitted
|
||||
bool faup_upload_unknown_commb; // faup1090: should we upload Comm-B messages that weren't in a recognized format?
|
||||
|
||||
int json_aircraft_history_next;
|
||||
struct {
|
||||
|
|
@ -394,6 +416,8 @@ struct _Modes { // Internal state
|
|||
float adaptive_min_gain_db;
|
||||
float adaptive_max_gain_db;
|
||||
|
||||
float adaptive_duty_cycle;
|
||||
|
||||
bool adaptive_burst_control;
|
||||
float adaptive_burst_alpha;
|
||||
unsigned adaptive_burst_change_delay;
|
||||
|
|
@ -609,6 +633,22 @@ struct modesMessage {
|
|||
|
||||
nav_modes_t modes;
|
||||
} nav;
|
||||
|
||||
// BDS 4,4 MRAR
|
||||
unsigned mrar_source_valid : 1;
|
||||
unsigned wind_valid : 1;
|
||||
unsigned temperature_valid : 1;
|
||||
unsigned pressure_valid : 1;
|
||||
unsigned turbulence_valid : 1;
|
||||
unsigned humidity_valid : 1;
|
||||
|
||||
mrar_source_t mrar_source;
|
||||
float wind_speed; // kts
|
||||
float wind_dir; // degrees
|
||||
float temperature; // degrees C
|
||||
float pressure; // hPa
|
||||
hazard_t turbulence; // NIL/LIGHT/MODERATE/SEVERE
|
||||
float humidity; // 0-100 %
|
||||
};
|
||||
|
||||
// This one needs modesMessage:
|
||||
|
|
|
|||
44
mode_s.c
44
mode_s.c
|
|
@ -1681,6 +1681,8 @@ static const char *commb_format_to_string(commb_format_t format) {
|
|||
return "empty response";
|
||||
case COMMB_AMBIGUOUS:
|
||||
return "ambiguous format";
|
||||
case COMMB_NOT_DECODED:
|
||||
return "not decoded";
|
||||
case COMMB_DATALINK_CAPS:
|
||||
return "BDS1,0 Datalink capabilities";
|
||||
case COMMB_GICB_CAPS:
|
||||
|
|
@ -1695,6 +1697,10 @@ static const char *commb_format_to_string(commb_format_t format) {
|
|||
return "BDS5,0 Track and turn report";
|
||||
case COMMB_HEADING_SPEED:
|
||||
return "BDS6,0 Heading and speed report";
|
||||
case COMMB_MRAR:
|
||||
return "BDS4,4 Meterological routine air report";
|
||||
case COMMB_AIRBORNE_POSITION:
|
||||
return "BDS0,5 Extended squitter airborne position";
|
||||
default:
|
||||
return "unknown format";
|
||||
}
|
||||
|
|
@ -1748,6 +1754,29 @@ static const char *emergency_to_string(emergency_t emergency)
|
|||
}
|
||||
}
|
||||
|
||||
static const char *mrar_source_to_string(mrar_source_t source)
|
||||
{
|
||||
switch (source) {
|
||||
case MRAR_SOURCE_INVALID: return "invalid";
|
||||
case MRAR_SOURCE_INS: return "INS";
|
||||
case MRAR_SOURCE_GNSS: return "GNSS";
|
||||
case MRAR_SOURCE_DMEDME: return "DME/DME";
|
||||
case MRAR_SOURCE_VORDME: return "VOR/DME";
|
||||
default: return "reserved";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *hazard_to_string(hazard_t hazard)
|
||||
{
|
||||
switch (hazard) {
|
||||
case HAZARD_NIL: return "nil";
|
||||
case HAZARD_LIGHT: return "light";
|
||||
case HAZARD_MODERATE: return "moderate";
|
||||
case HAZARD_SEVERE: return "severe";
|
||||
default: return "invalid hazard severity";
|
||||
}
|
||||
}
|
||||
|
||||
static void print_hex_bytes(unsigned char *data, size_t len) {
|
||||
size_t i;
|
||||
for (i = 0; i < len; ++i) {
|
||||
|
|
@ -2213,6 +2242,21 @@ void displayModesMessage(struct modesMessage *mm) {
|
|||
printf(" Emergency/priority: %s\n", emergency_to_string(mm->emergency));
|
||||
}
|
||||
|
||||
if (mm->mrar_source_valid)
|
||||
printf(" MRAR FOM/Source: %s\n", mrar_source_to_string(mm->mrar_source));
|
||||
if (mm->wind_valid) {
|
||||
printf(" Wind speed: %.0f kt\n", mm->wind_speed);
|
||||
printf(" Wind direction: %.1f degrees\n", mm->wind_dir);
|
||||
}
|
||||
if (mm->temperature_valid)
|
||||
printf(" Air temperature: %.1f degrees C\n", mm->temperature);
|
||||
if (mm->pressure_valid)
|
||||
printf(" Static pressure: %.0f hPa\n", mm->pressure);
|
||||
if (mm->turbulence_valid)
|
||||
printf(" Turbulence: %s\n", hazard_to_string(mm->turbulence));
|
||||
if (mm->humidity_valid)
|
||||
printf(" Humidity: %.0f%%\n", mm->humidity);
|
||||
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
|
|
|||
132
net_io.c
132
net_io.c
|
|
@ -839,12 +839,14 @@ static void modesSendStratuxOutput(struct modesMessage *mm, struct aircraft *a)
|
|||
"\"TypeCode\":%d,"
|
||||
"\"SubtypeCode\":%d,"
|
||||
"\"SignalLevel\":%f,"
|
||||
"\"Gain\":%f,"
|
||||
"\"IsMlat\":%s,",
|
||||
mm->addr,
|
||||
mm->msgtype, cacf,
|
||||
mm->metype,
|
||||
mm->mesub,
|
||||
mm->signalLevel, // what precision and range is needed for RSSI?
|
||||
sdrGetGainDb(sdrGetGain()),
|
||||
is_mlat_str);
|
||||
|
||||
//// callsign
|
||||
|
|
@ -1126,7 +1128,7 @@ static int handleFaupCommand(struct client *c, char *p) {
|
|||
|
||||
// Traverse through message for commands
|
||||
while (msg_field != NULL) {
|
||||
if (strcmp(msg_field, "upload_rate_multiplier") == 0) {
|
||||
if (!strcmp(msg_field, "upload_rate_multiplier")) {
|
||||
msg_field = strtok (NULL, "\t");
|
||||
multiplier = atof(msg_field);
|
||||
|
||||
|
|
@ -1140,6 +1142,14 @@ static int handleFaupCommand(struct client *c, char *p) {
|
|||
Modes.faup_rate_multiplier = multiplier;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!strcmp(msg_field, "upload_unknown_commb")) {
|
||||
msg_field = strtok (NULL, "\t");
|
||||
unsigned enable = atoi(msg_field);
|
||||
fprintf(stderr, "handleFaupCommand(): %s upload of unknown Comm-B messages\n", enable ? "Enabling" : "Disabling");
|
||||
Modes.faup_upload_unknown_commb = enable;
|
||||
break;
|
||||
}
|
||||
msg_field = strtok (NULL, "\t");
|
||||
}
|
||||
|
||||
|
|
@ -1604,6 +1614,29 @@ static const char *nav_altitude_source_enum_string(nav_altitude_source_t src)
|
|||
}
|
||||
}
|
||||
|
||||
static const char *mrar_source_enum_string(mrar_source_t src)
|
||||
{
|
||||
switch (src) {
|
||||
case MRAR_SOURCE_INVALID: return "invalid";
|
||||
case MRAR_SOURCE_INS: return "ins";
|
||||
case MRAR_SOURCE_GNSS: return "gnss";
|
||||
case MRAR_SOURCE_DMEDME: return "dmedme";
|
||||
case MRAR_SOURCE_VORDME: return "vordme";
|
||||
default: return "reserved";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *hazard_enum_string(hazard_t hazard)
|
||||
{
|
||||
switch (hazard) {
|
||||
case HAZARD_NIL: return "nil";
|
||||
case HAZARD_LIGHT: return "light";
|
||||
case HAZARD_MODERATE: return "moderate";
|
||||
case HAZARD_SEVERE: return "severe";
|
||||
default: return "invalid";
|
||||
}
|
||||
}
|
||||
|
||||
char *generateAircraftJson(const char *url_path, int *len) {
|
||||
uint64_t now = mstime();
|
||||
struct aircraft *a;
|
||||
|
|
@ -1707,12 +1740,23 @@ char *generateAircraftJson(const char *url_path, int *len) {
|
|||
p = safe_snprintf(p, end, ",\"gva\":%u", a->gva);
|
||||
if (trackDataValid(&a->sda_valid))
|
||||
p = safe_snprintf(p, end, ",\"sda\":%u", a->sda);
|
||||
if (trackDataValid(&a->mrar_source_valid))
|
||||
p = safe_snprintf(p, end, ",\"mrar_source\":\"%s\"", mrar_source_enum_string(a->mrar_source));
|
||||
if (trackDataValid(&a->wind_valid))
|
||||
p = safe_snprintf(p, end, ",\"wind_speed\":%.0f,\"wind_dir\":%.1f", a->wind_speed, a->wind_dir);
|
||||
if (trackDataValid(&a->temperature_valid))
|
||||
p = safe_snprintf(p, end, ",\"temperature\":%.2f", a->temperature);
|
||||
if (trackDataValid(&a->pressure_valid))
|
||||
p = safe_snprintf(p, end, ",\"pressure\":%.0f", a->pressure);
|
||||
if (trackDataValid(&a->turbulence_valid))
|
||||
p = safe_snprintf(p, end, ",\"turbulence\":\"%s\"", hazard_enum_string(a->turbulence));
|
||||
if (trackDataValid(&a->humidity_valid))
|
||||
p = safe_snprintf(p, end, ",\"humidity\":%.1f", a->humidity);
|
||||
if (a->modeA_hit)
|
||||
p = safe_snprintf(p, end, ",\"modea\":true");
|
||||
if (a->modeC_hit)
|
||||
p = safe_snprintf(p, end, ",\"modec\":true");
|
||||
|
||||
|
||||
p = safe_snprintf(p, end, ",\"mlat\":");
|
||||
p = append_flags(p, end, a, SOURCE_MLAT);
|
||||
p = safe_snprintf(p, end, ",\"tisb\":");
|
||||
|
|
@ -1993,6 +2037,30 @@ char *generateHistoryJson(const char *url_path, int *len)
|
|||
return strdup(Modes.json_aircraft_history[history_index].content);
|
||||
}
|
||||
|
||||
static void ratelimitWriteError(const char *format, ...)
|
||||
{
|
||||
static uint64_t lastError = 0;
|
||||
static unsigned suppressed = 0;
|
||||
|
||||
uint64_t now = mstime();
|
||||
if (now - lastError < 60000) {
|
||||
++suppressed;
|
||||
return;
|
||||
}
|
||||
|
||||
lastError = now;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vfprintf(stderr, format, ap);
|
||||
if (suppressed) {
|
||||
fprintf(stderr, " (%u more error messages suppressed)", suppressed);
|
||||
suppressed = 0;
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
// Write JSON to file
|
||||
void writeJsonToFile(const char *file, char * (*generator) (const char *,int*))
|
||||
{
|
||||
|
|
@ -2010,8 +2078,10 @@ void writeJsonToFile(const char *file, char * (*generator) (const char *,int*))
|
|||
snprintf(tmppath, PATH_MAX, "%s/%s.XXXXXX", Modes.json_dir, file);
|
||||
tmppath[PATH_MAX-1] = 0;
|
||||
fd = mkstemp(tmppath);
|
||||
if (fd < 0)
|
||||
if (fd < 0) {
|
||||
ratelimitWriteError("failed to create %s (while updating %s/%s): %s", tmppath, Modes.json_dir, file, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
mask = umask(0);
|
||||
umask(mask);
|
||||
|
|
@ -2021,15 +2091,23 @@ void writeJsonToFile(const char *file, char * (*generator) (const char *,int*))
|
|||
pathbuf[PATH_MAX-1] = 0;
|
||||
content = generator(pathbuf, &len);
|
||||
|
||||
if (write(fd, content, len) != len)
|
||||
if (write(fd, content, len) != len) {
|
||||
ratelimitWriteError("failed to write to %s (while updating %s/%s): %s", tmppath, Modes.json_dir, file, strerror(errno));
|
||||
goto error_1;
|
||||
}
|
||||
|
||||
if (close(fd) < 0)
|
||||
if (close(fd) < 0) {
|
||||
ratelimitWriteError("failed to write to %s (while updating %s/%s): %s", tmppath, Modes.json_dir, file, strerror(errno));
|
||||
goto error_2;
|
||||
}
|
||||
|
||||
snprintf(pathbuf, PATH_MAX, "%s/%s", Modes.json_dir, file);
|
||||
pathbuf[PATH_MAX-1] = 0;
|
||||
rename(tmppath, pathbuf);
|
||||
if (rename(tmppath, pathbuf) < 0) {
|
||||
ratelimitWriteError("failed to rename %s to %s: %s", tmppath, pathbuf, strerror(errno));
|
||||
goto error_2;
|
||||
}
|
||||
|
||||
free(content);
|
||||
return;
|
||||
|
||||
|
|
@ -2257,7 +2335,7 @@ __attribute__ ((format (printf,4,5))) static char *appendFATSV(char *p, char *en
|
|||
}
|
||||
|
||||
#define TSV_MAX_PACKET_SIZE 800
|
||||
#define TSV_VERSION "8E"
|
||||
#define TSV_VERSION "9E"
|
||||
|
||||
static void writeFATSVPositionUpdate(float lat, float lon, float alt)
|
||||
{
|
||||
|
|
@ -2352,6 +2430,23 @@ static void writeFATSVEvent(struct modesMessage *mm, struct aircraft *a)
|
|||
}
|
||||
break;
|
||||
|
||||
case COMMB_GICB_CAPS:
|
||||
// BDS 1,7: common usage GICB capability report
|
||||
if (memcmp(mm->MB, a->fatsv_emitted_bds_17, 7) != 0) {
|
||||
memcpy(a->fatsv_emitted_bds_17, mm->MB, 7);
|
||||
writeFATSVEventMessage(mm, "gicb_caps", mm->MB, 7);
|
||||
}
|
||||
break;
|
||||
|
||||
case COMMB_UNKNOWN:
|
||||
// If enabled, upload raw unrecognized Comm-B messages
|
||||
// for server-side analysis
|
||||
if (Modes.faup_upload_unknown_commb && memcmp(mm->MB, a->fatsv_emitted_unknown_commb, 7) != 0) {
|
||||
memcpy(a->fatsv_emitted_unknown_commb, mm->MB, 7);
|
||||
writeFATSVEventMessage(mm, "unknown_commb", mm->MB, 7);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// nothing
|
||||
break;
|
||||
|
|
@ -2526,7 +2621,13 @@ static void writeFATSV()
|
|||
(airgroundValid && a->airground == AG_AIRBORNE && a->fatsv_emitted_airground == AG_GROUND) ||
|
||||
(airgroundValid && a->airground == AG_GROUND && a->fatsv_emitted_airground == AG_AIRBORNE) ||
|
||||
(squawkValid && a->squawk != a->fatsv_emitted_squawk) ||
|
||||
(trackDataValid(&a->emergency_valid) && a->emergency != a->fatsv_emitted_emergency);
|
||||
(trackDataValid(&a->emergency_valid) && a->emergency != a->fatsv_emitted_emergency) ||
|
||||
(trackDataValid(&a->mrar_source_valid) && a->mrar_source_valid.updated > a->fatsv_last_emitted) ||
|
||||
(trackDataValid(&a->wind_valid) && a->wind_valid.updated > a->fatsv_last_emitted) ||
|
||||
(trackDataValid(&a->pressure_valid) && a->pressure_valid.updated > a->fatsv_last_emitted) ||
|
||||
(trackDataValid(&a->temperature_valid) && a->temperature_valid.updated > a->fatsv_last_emitted) ||
|
||||
(trackDataValid(&a->turbulence_valid) && a->turbulence_valid.updated > a->fatsv_last_emitted) ||
|
||||
(trackDataValid(&a->humidity_valid) && a->humidity_valid.updated > a->fatsv_last_emitted);
|
||||
|
||||
uint64_t minAge;
|
||||
double adjustedMinAge;
|
||||
|
|
@ -2628,10 +2729,17 @@ static void writeFATSV()
|
|||
p = appendFATSVMeta(p, end, "nav_alt_mcp", a, &a->nav_altitude_mcp_valid, "%u", a->nav_altitude_mcp);
|
||||
p = appendFATSVMeta(p, end, "nav_alt_fms", a, &a->nav_altitude_fms_valid, "%u", a->nav_altitude_fms);
|
||||
p = appendFATSVMeta(p, end, "nav_alt_src", a, &a->nav_altitude_src_valid, "%s", nav_altitude_source_enum_string(a->nav_altitude_src));
|
||||
p = appendFATSVMeta(p, end, "nav_heading", a, &a->nav_heading_valid, "%.1f", a->nav_heading);
|
||||
p = appendFATSVMeta(p, end, "nav_modes", a, &a->nav_modes_valid, "{%s}", nav_modes_flags_string(a->nav_modes));
|
||||
p = appendFATSVMeta(p, end, "nav_qnh", a, &a->nav_qnh_valid, "%.1f", a->nav_qnh);
|
||||
p = appendFATSVMeta(p, end, "emergency", a, &a->emergency_valid, "%s", emergency_enum_string(a->emergency));
|
||||
p = appendFATSVMeta(p, end, "nav_heading", a, &a->nav_heading_valid, "%.1f", a->nav_heading);
|
||||
p = appendFATSVMeta(p, end, "nav_modes", a, &a->nav_modes_valid, "{%s}", nav_modes_flags_string(a->nav_modes));
|
||||
p = appendFATSVMeta(p, end, "nav_qnh", a, &a->nav_qnh_valid, "%.1f", a->nav_qnh);
|
||||
p = appendFATSVMeta(p, end, "emergency", a, &a->emergency_valid, "%s", emergency_enum_string(a->emergency));
|
||||
p = appendFATSVMeta(p, end, "mrar_source", a, &a->mrar_source_valid, "%s", mrar_source_enum_string(a->mrar_source));
|
||||
p = appendFATSVMeta(p, end, "wind_speed", a, &a->wind_valid, "%.0f", a->wind_speed);
|
||||
p = appendFATSVMeta(p, end, "wind_dir", a, &a->wind_valid, "%.1f", a->wind_dir);
|
||||
p = appendFATSVMeta(p, end, "temperature", a, &a->temperature_valid, "%.2f", a->temperature);
|
||||
p = appendFATSVMeta(p, end, "pressure", a, &a->pressure_valid, "%.0f", a->pressure);
|
||||
p = appendFATSVMeta(p, end, "turbulence", a, &a->turbulence_valid, "%s", hazard_enum_string(a->turbulence));
|
||||
p = appendFATSVMeta(p, end, "humidity", a, &a->humidity_valid, "%.0f", a->humidity);
|
||||
|
||||
// if we didn't get anything interesting, bail out.
|
||||
// We don't need to do anything special to unwind prepareWrite().
|
||||
|
|
|
|||
|
|
@ -279,7 +279,7 @@ bool limesdrOpen(void)
|
|||
goto error;
|
||||
}
|
||||
} else {
|
||||
if (Modes.gain == MODES_MAX_GAIN) {
|
||||
if (Modes.gain == MODES_DEFAULT_GAIN) {
|
||||
if (LMS_SetNormalizedGain(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, 1.0)) {
|
||||
limesdrLogHandler(LMS_LOG_ERROR, "unable to set gain");
|
||||
goto error;
|
||||
|
|
|
|||
10
sdr_rtlsdr.c
10
sdr_rtlsdr.c
|
|
@ -53,7 +53,7 @@
|
|||
|
||||
#include <rtl-sdr.h>
|
||||
|
||||
#ifdef __arm__
|
||||
#if defined(__arm__) || defined(__aarch64__)
|
||||
// Assume we need to use a bounce buffer to avoid performance problems on Pis running kernel 5.x and using zerocopy
|
||||
# define USE_BOUNCE_BUFFER
|
||||
#endif
|
||||
|
|
@ -255,17 +255,17 @@ bool rtlsdrOpen(void)
|
|||
RTLSDR.gains = gains;
|
||||
|
||||
int selected = -1;
|
||||
if (Modes.gain == MODES_AUTO_GAIN) {
|
||||
if (Modes.gain == MODES_LEGACY_AUTO_GAIN) {
|
||||
selected = numgains;
|
||||
} else if (Modes.gain == MODES_MAX_GAIN) {
|
||||
} else if (Modes.gain == MODES_DEFAULT_GAIN) {
|
||||
selected = numgains - 1;
|
||||
} else {
|
||||
for (int i = 0; i < numgains; ++i) {
|
||||
for (int i = 0; i <= numgains; ++i) {
|
||||
if (selected == -1 || fabs(gains[i]/10.0 - Modes.gain) < fabs(gains[selected]/10.0 - Modes.gain))
|
||||
selected = i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
rtlsdrSetGain(selected);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -571,7 +571,7 @@ class Generator(object):
|
|||
|
||||
def render(self, template_path, output_path, **kwargs):
|
||||
t = self.templates.get_template(template_path)
|
||||
result = t.render(gen=self, current_dir=os.path.dirname(output_path), **kwargs)
|
||||
result = t.render(gen=self, current_dir=os.path.dirname(output_path), **kwargs).replace('\r\n', '\n')
|
||||
|
||||
if os.path.exists(output_path):
|
||||
with open(output_path, 'r') as f:
|
||||
|
|
|
|||
|
|
@ -15,6 +15,16 @@
|
|||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
//On Windows platform, separate functions for allocating and freeing aligned memory must be used
|
||||
#ifdef _WIN32
|
||||
# include <malloc.h>
|
||||
# define util_aligned_alloc(alignment,size) (_aligned_malloc(size, alignment))
|
||||
# define util_aligned_free(ptr) (_aligned_free(ptr))
|
||||
#else
|
||||
# define util_aligned_alloc(alignment,size) (aligned_alloc(alignment,size))
|
||||
# define util_aligned_free(ptr) (free(ptr))
|
||||
#endif
|
||||
|
||||
#include "${os.path.relpath(gen.generated_include_path, current_dir)}"
|
||||
|
||||
typedef struct timespec starch_benchmark_time;
|
||||
|
|
@ -79,7 +89,7 @@ void *starch_benchmark_aligned_alloc(size_t alignment, size_t type_alignment, si
|
|||
* of a more restrictive larger alignment)
|
||||
*/
|
||||
size_t header_size = (use_alignment < sizeof(void*) ? sizeof(void*) : use_alignment);
|
||||
char *block_ptr = aligned_alloc(use_alignment, header_size + size + use_alignment);
|
||||
char *block_ptr = util_aligned_alloc(use_alignment, header_size + size + use_alignment);
|
||||
if (!block_ptr) {
|
||||
fprintf(stderr, "STARCH_BENCHMARK_ALLOC of %zu bytes failed: %s\n", size, strerror(errno));
|
||||
return NULL;
|
||||
|
|
@ -102,7 +112,7 @@ void starch_benchmark_aligned_free(void *user_ptr)
|
|||
if (!user_ptr)
|
||||
return;
|
||||
void **stash = (void**)user_ptr - 1;
|
||||
free(*stash);
|
||||
util_aligned_free(*stash);
|
||||
}
|
||||
|
||||
static bool starch_benchmark_flavor_in_list(const char *flavor, const starch_benchmark_flavor_list *list)
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
# $(STARCH_BENCHMARK_OBJ): object files providing a standalone benchmarking app (link all of $(STARCH_OBJS) too)
|
||||
# explicit build rules for each object file listed in $(STARCH_OBJS)
|
||||
|
||||
MKDIR_P = mkdir -p
|
||||
STARCH_CFLAGS := -D${mix.macro}
|
||||
<%
|
||||
import os
|
||||
|
|
@ -35,7 +36,8 @@ STARCH_CFLAGS := -D${mix.macro}
|
|||
o_files.append(o_file)
|
||||
%>
|
||||
${o_file}: ${c_file} ${impl_c_files}
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) ${flavor.cflags} ${c_file} -o ${o_file}
|
||||
@$(MKDIR_P) $(dir $(STARCH_OBJ_PATH)${o_file})
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) ${flavor.cflags} ${c_file} -o $(STARCH_OBJ_PATH)${o_file}
|
||||
% endfor
|
||||
<%
|
||||
c_file = os.path.relpath(gen.generated_dispatcher_path, gen.runtime_dir)
|
||||
|
|
@ -43,7 +45,8 @@ ${o_file}: ${c_file} ${impl_c_files}
|
|||
o_files.append(o_file)
|
||||
%>
|
||||
${o_file}: ${c_file} ${impl_c_files}
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) ${c_file} -o ${o_file}
|
||||
@$(MKDIR_P) $(dir $(STARCH_OBJ_PATH)${o_file})
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) ${c_file} -o $(STARCH_OBJ_PATH)${o_file}
|
||||
|
||||
STARCH_OBJS := ${' '.join(o_files)}
|
||||
|
||||
|
|
@ -52,6 +55,7 @@ STARCH_OBJS := ${' '.join(o_files)}
|
|||
o_file = os.path.splitext(c_file)[0] + '.o'
|
||||
%>
|
||||
${o_file}: ${c_file} ${benchmark_c_files}
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) ${c_file} -o ${o_file}
|
||||
@$(MKDIR_P) $(dir $(STARCH_OBJ_PATH)${o_file})
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) ${c_file} -o $(STARCH_OBJ_PATH)${o_file}
|
||||
|
||||
STARCH_BENCHMARK_OBJ := ${o_file}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
37
track.c
37
track.c
|
|
@ -130,6 +130,12 @@ static struct aircraft *trackCreateAircraft(struct modesMessage *mm) {
|
|||
F(sil, 60, 70); // ADS-B only
|
||||
F(gva, 60, 70); // ADS-B only
|
||||
F(sda, 60, 70); // ADS-B only
|
||||
F(mrar_source, 60, 70); // Comm-B only
|
||||
F(wind, 60, 70); // Comm-B only
|
||||
F(temperature, 60, 70); // Comm-B only
|
||||
F(pressure, 60, 70); // Comm-B only
|
||||
F(turbulence, 60, 70); // Comm-B only
|
||||
F(humidity, 60, 70); // Comm-B only
|
||||
#undef F
|
||||
|
||||
Modes.stats_current.unique_aircraft++;
|
||||
|
|
@ -1237,6 +1243,31 @@ struct aircraft *trackUpdateFromMessage(struct modesMessage *mm)
|
|||
a->sda = mm->accuracy.sda;
|
||||
}
|
||||
|
||||
if (mm->mrar_source_valid && accept_data(&a->mrar_source_valid, mm->source)) {
|
||||
a->mrar_source = mm->mrar_source;
|
||||
}
|
||||
|
||||
if (mm->wind_valid && accept_data(&a->wind_valid, mm->source)) {
|
||||
a->wind_speed = mm->wind_speed;
|
||||
a->wind_dir = mm->wind_dir;
|
||||
}
|
||||
|
||||
if (mm->temperature_valid && accept_data(&a->temperature_valid, mm->source)) {
|
||||
a->temperature = mm->temperature;
|
||||
}
|
||||
|
||||
if (mm->pressure_valid && accept_data(&a->pressure_valid, mm->source)) {
|
||||
a->pressure = mm->pressure;
|
||||
}
|
||||
|
||||
if (mm->turbulence_valid && accept_data(&a->turbulence_valid, mm->source)) {
|
||||
a->turbulence = mm->turbulence;
|
||||
}
|
||||
|
||||
if (mm->humidity_valid && accept_data(&a->humidity_valid, mm->source)) {
|
||||
a->humidity = mm->humidity;
|
||||
}
|
||||
|
||||
// Now handle derived data
|
||||
|
||||
// derive geometric altitude if we have baro + delta
|
||||
|
|
@ -1400,6 +1431,12 @@ static void trackRemoveStaleAircraft(uint64_t now)
|
|||
EXPIRE(sil);
|
||||
EXPIRE(gva);
|
||||
EXPIRE(sda);
|
||||
EXPIRE(mrar_source);
|
||||
EXPIRE(wind);
|
||||
EXPIRE(temperature);
|
||||
EXPIRE(pressure);
|
||||
EXPIRE(turbulence);
|
||||
EXPIRE(humidity);
|
||||
#undef EXPIRE
|
||||
prev = a; a = a->next;
|
||||
}
|
||||
|
|
|
|||
18
track.h
18
track.h
|
|
@ -226,6 +226,22 @@ struct aircraft {
|
|||
unsigned gva : 2; // GVA from opstatus
|
||||
unsigned sda : 2; // SDA from opstatus
|
||||
|
||||
// data extracted from MRAR
|
||||
data_validity mrar_source_valid;
|
||||
data_validity wind_valid; // speed and direction
|
||||
data_validity pressure_valid;
|
||||
data_validity temperature_valid;
|
||||
data_validity turbulence_valid;
|
||||
data_validity humidity_valid;
|
||||
|
||||
mrar_source_t mrar_source;
|
||||
float wind_speed;
|
||||
float wind_dir;
|
||||
float pressure;
|
||||
float temperature;
|
||||
hazard_t turbulence;
|
||||
float humidity;
|
||||
|
||||
int modeA_hit; // did our squawk match a possible mode A reply in the last check period?
|
||||
int modeC_hit; // did our altitude match a possible mode C reply in the last check period?
|
||||
|
||||
|
|
@ -250,7 +266,9 @@ struct aircraft {
|
|||
nav_modes_t fatsv_emitted_nav_modes; // -"- enabled navigation modes
|
||||
float fatsv_emitted_nav_qnh; // -"- altimeter setting
|
||||
unsigned char fatsv_emitted_bds_10[7]; // -"- BDS 1,0 message
|
||||
unsigned char fatsv_emitted_bds_17[7]; // -"- BDS 1,7 message
|
||||
unsigned char fatsv_emitted_bds_30[7]; // -"- BDS 3,0 message
|
||||
unsigned char fatsv_emitted_unknown_commb[7]; // -"- unrecognized Comm-B message
|
||||
unsigned char fatsv_emitted_es_status[7]; // -"- ES operational status message
|
||||
unsigned char fatsv_emitted_es_acas_ra[7]; // -"- ES ACAS RA report message
|
||||
char fatsv_emitted_callsign[9]; // -"- callsign
|
||||
|
|
|
|||
Loading…
Reference in New Issue