Compare commits
111 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
849a3b7329 | |
|
|
b842f4a8ed | |
|
|
6fc48a8cef | |
|
|
2e83305229 | |
|
|
d0e87cc219 | |
|
|
ac7b5759f7 | |
|
|
350664a13a | |
|
|
f24c932cf8 | |
|
|
c35135cabf | |
|
|
86885c2480 | |
|
|
3be128877d | |
|
|
a13356d801 | |
|
|
855f71918e | |
|
|
f5185cbebe | |
|
|
765b295479 | |
|
|
778d85e75f | |
|
|
fb959f0fc7 | |
|
|
fec0da4f0b | |
|
|
52cdd32d0f | |
|
|
4601566886 | |
|
|
23f5dfef2c | |
|
|
42a5c2a978 | |
|
|
65cd5fe441 | |
|
|
f932baa5fa | |
|
|
fa8a066b4c | |
|
|
b645f7d4f2 | |
|
|
bc72177c8b | |
|
|
24c0248fc0 | |
|
|
cdbd6c77a9 | |
|
|
9b2cd0a5ba | |
|
|
059e48b82b | |
|
|
5f7e7cf8e0 | |
|
|
752a7aeac0 | |
|
|
08c7ccbc8e | |
|
|
9788588aba | |
|
|
8b9dd42676 | |
|
|
14e6d5c3fa | |
|
|
e8eeac4654 | |
|
|
abf8fa2b00 | |
|
|
06bc3c34cf | |
|
|
88fec00f17 | |
|
|
ae042eeb27 | |
|
|
f45b2c6475 | |
|
|
2ba2f4da71 | |
|
|
29a6ae5102 | |
|
|
0aac23e049 | |
|
|
ef70374126 | |
|
|
7d552a2ede | |
|
|
8b0e8ce6e3 | |
|
|
e02d0d5ffa | |
|
|
871a7e685f | |
|
|
dd53b36bdf | |
|
|
26924e4efe | |
|
|
6785c56348 | |
|
|
21d1fe0f11 | |
|
|
3367cc5a82 | |
|
|
fe36349083 | |
|
|
e0f794b1a5 | |
|
|
95ab1c0faa | |
|
|
fab8081322 | |
|
|
9d4e2230d2 | |
|
|
825f959e4d | |
|
|
c148fdca84 | |
|
|
9f146fcb71 | |
|
|
cdc818a9f3 | |
|
|
e3a8e00412 | |
|
|
6b8cac3922 | |
|
|
899ee2530c | |
|
|
d6405ddefd | |
|
|
e058929977 | |
|
|
7b1771cdad | |
|
|
017e5d391b | |
|
|
5bd1718bb2 | |
|
|
f3e498a62a | |
|
|
d4b3b03fe0 | |
|
|
ec69b94544 | |
|
|
3069f3d99f | |
|
|
4cf8eb254e | |
|
|
be3c9930f1 | |
|
|
e0f7a33df4 | |
|
|
9e671a14e4 | |
|
|
4e21610c50 | |
|
|
603da245bd | |
|
|
6e5f2595e0 | |
|
|
2480e5169c | |
|
|
1cb4284e6c | |
|
|
ac97423249 | |
|
|
fd8f2d77e1 | |
|
|
b3172181d5 | |
|
|
56625449e8 | |
|
|
b775f2b326 | |
|
|
8d877eeed8 | |
|
|
88741d097b | |
|
|
24c425c968 | |
|
|
acde5b4a91 | |
|
|
f7b6f7aefc | |
|
|
a4cd5bb42d | |
|
|
465d436174 | |
|
|
223283863f | |
|
|
b4acf08738 | |
|
|
265055106b | |
|
|
80acb91dbc | |
|
|
3d013c4251 | |
|
|
86bb40a31c | |
|
|
8dd83d2e7e | |
|
|
c433463392 | |
|
|
455896e86d | |
|
|
037fe4f37f | |
|
|
c97b83d3ed | |
|
|
462dee56f3 | |
|
|
d3c692f630 |
|
|
@ -8,7 +8,7 @@ node(label: 'raspberrypi') {
|
|||
durabilityHint(hint: 'PERFORMANCE_OPTIMIZED')
|
||||
])
|
||||
|
||||
def dists = ["buster", "stretch", "jessie"]
|
||||
def dists = ["bullseye", "buster", "stretch"]
|
||||
def srcdir = "${WORKSPACE}/src"
|
||||
|
||||
stage('Checkout') {
|
||||
|
|
|
|||
96
Makefile
96
Makefile
|
|
@ -2,10 +2,10 @@ PROGNAME=dump1090
|
|||
|
||||
DUMP1090_VERSION ?= unknown
|
||||
|
||||
CPPFLAGS += -I. -DMODES_DUMP1090_VERSION=\"$(DUMP1090_VERSION)\" -DMODES_DUMP1090_VARIANT=\"dump1090-fa\"
|
||||
CFLAGS ?= -O3 -g
|
||||
DUMP1090_CFLAGS := -std=c11 -fno-common -Wall -Wmissing-declarations -Werror -W
|
||||
DUMP1090_CPPFLAGS := -I. -D_POSIX_C_SOURCE=200112L -DMODES_DUMP1090_VERSION=\"$(DUMP1090_VERSION)\" -DMODES_DUMP1090_VARIANT=\"dump1090-fa\"
|
||||
|
||||
DIALECT = -std=c11
|
||||
CFLAGS += $(DIALECT) -O3 -g -Wall -Wmissing-declarations -Werror -W -D_DEFAULT_SOURCE -fno-common
|
||||
LIBS = -lpthread -lm
|
||||
SDR_OBJ = cpu.o sdr.o fifo.o sdr_ifile.o dsp/helpers/tables.o
|
||||
|
||||
|
|
@ -39,10 +39,14 @@ else
|
|||
LIMESDR ?= no
|
||||
endif
|
||||
|
||||
UNAME := $(shell uname)
|
||||
HOST_UNAME := $(shell uname)
|
||||
HOST_ARCH := $(shell uname -m)
|
||||
|
||||
UNAME ?= $(HOST_UNAME)
|
||||
ARCH ?= $(HOST_ARCH)
|
||||
|
||||
ifeq ($(UNAME), Linux)
|
||||
CPPFLAGS += -D_DEFAULT_SOURCE
|
||||
DUMP1090_CPPFLAGS += -D_DEFAULT_SOURCE
|
||||
LIBS += -lrt
|
||||
LIBS_USB += -lusb-1.0
|
||||
LIBS_CURSES := -lncurses
|
||||
|
|
@ -51,32 +55,35 @@ endif
|
|||
|
||||
ifeq ($(UNAME), Darwin)
|
||||
ifneq ($(shell sw_vers -productVersion | egrep '^10\.([0-9]|1[01])\.'),) # Mac OS X ver <= 10.11
|
||||
CPPFLAGS += -DMISSING_GETTIME
|
||||
DUMP1090_CPPFLAGS += -DMISSING_GETTIME
|
||||
COMPAT += compat/clock_gettime/clock_gettime.o
|
||||
endif
|
||||
CPPFLAGS += -DMISSING_NANOSLEEP
|
||||
DUMP1090_CPPFLAGS += -DMISSING_NANOSLEEP
|
||||
COMPAT += compat/clock_nanosleep/clock_nanosleep.o
|
||||
LIBS_USB += -lusb-1.0
|
||||
LIBS_CURSES := -lncurses
|
||||
CPUFEATURES ?= yes
|
||||
# cpufeatures reportedly does not work (yet) on darwin arm64
|
||||
ifneq ($(ARCH),arm64)
|
||||
CPUFEATURES ?= yes
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(UNAME), OpenBSD)
|
||||
CPPFLAGS += -DMISSING_NANOSLEEP
|
||||
DUMP1090_CPPFLAGS += -DMISSING_NANOSLEEP
|
||||
COMPAT += compat/clock_nanosleep/clock_nanosleep.o
|
||||
LIBS_USB += -lusb-1.0
|
||||
LIBS_CURSES := -lncurses
|
||||
endif
|
||||
|
||||
ifeq ($(UNAME), FreeBSD)
|
||||
CPPFLAGS += -D_DEFAULT_SOURCE
|
||||
DUMP1090_CPPFLAGS += -D_DEFAULT_SOURCE
|
||||
LIBS += -lrt
|
||||
LIBS_USB += -lusb
|
||||
LIBS_CURSES := -lncurses
|
||||
endif
|
||||
|
||||
ifeq ($(UNAME), NetBSD)
|
||||
CFLAGS += -D_DEFAULT_SOURCE
|
||||
DUMP1090_CPPFLAGS += -D_DEFAULT_SOURCE
|
||||
LIBS += -lrt
|
||||
LIBS_USB += -lusb-1.0
|
||||
LIBS_CURSES := -lcurses
|
||||
|
|
@ -86,7 +93,7 @@ CPUFEATURES ?= no
|
|||
|
||||
ifeq ($(CPUFEATURES),yes)
|
||||
include Makefile.cpufeatures
|
||||
CPPFLAGS += -DENABLE_CPUFEATURES -Icpu_features/include
|
||||
DUMP1090_CPPFLAGS += -DENABLE_CPUFEATURES -Icpu_features/include
|
||||
endif
|
||||
|
||||
RTLSDR ?= yes
|
||||
|
|
@ -94,10 +101,10 @@ BLADERF ?= yes
|
|||
|
||||
ifeq ($(RTLSDR), yes)
|
||||
SDR_OBJ += sdr_rtlsdr.o
|
||||
CPPFLAGS += -DENABLE_RTLSDR
|
||||
DUMP1090_CPPFLAGS += -DENABLE_RTLSDR
|
||||
|
||||
ifdef RTLSDR_PREFIX
|
||||
CPPFLAGS += -I$(RTLSDR_PREFIX)/include
|
||||
DUMP1090_CPPFLAGS += -I$(RTLSDR_PREFIX)/include
|
||||
ifeq ($(STATIC), yes)
|
||||
LIBS_SDR += -L$(RTLSDR_PREFIX)/lib -Wl,-Bstatic -lrtlsdr -Wl,-Bdynamic $(LIBS_USB)
|
||||
else
|
||||
|
|
@ -107,8 +114,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))
|
||||
DUMP1090_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
|
||||
|
|
@ -123,22 +133,22 @@ endif
|
|||
|
||||
ifeq ($(BLADERF), yes)
|
||||
SDR_OBJ += sdr_bladerf.o
|
||||
CPPFLAGS += -DENABLE_BLADERF
|
||||
CFLAGS += $(shell pkg-config --cflags libbladeRF)
|
||||
DUMP1090_CPPFLAGS += -DENABLE_BLADERF
|
||||
DUMP1090_CFLAGS += $(shell pkg-config --cflags libbladeRF)
|
||||
LIBS_SDR += $(shell pkg-config --libs libbladeRF)
|
||||
endif
|
||||
|
||||
ifeq ($(HACKRF), yes)
|
||||
SDR_OBJ += sdr_hackrf.o
|
||||
CPPFLAGS += -DENABLE_HACKRF
|
||||
CFLAGS += $(shell pkg-config --cflags libhackrf)
|
||||
DUMP1090_CPPFLAGS += -DENABLE_HACKRF
|
||||
DUMP1090_CFLAGS += $(shell pkg-config --cflags libhackrf)
|
||||
LIBS_SDR += $(shell pkg-config --libs libhackrf)
|
||||
endif
|
||||
|
||||
ifeq ($(LIMESDR), yes)
|
||||
SDR_OBJ += sdr_limesdr.o
|
||||
CPPFLAGS += -DENABLE_LIMESDR
|
||||
CFLAGS += $(shell pkg-config --cflags LimeSuite)
|
||||
DUMP1090_CPPFLAGS += -DENABLE_LIMESDR
|
||||
DUMP1090_CFLAGS += $(shell pkg-config --cflags LimeSuite)
|
||||
LIBS_SDR += $(shell pkg-config --libs LimeSuite)
|
||||
endif
|
||||
|
||||
|
|
@ -147,36 +157,42 @@ endif
|
|||
## starch (runtime DSP code selection) mix, architecture-specific
|
||||
##
|
||||
|
||||
ARCH ?= $(shell uname -m)
|
||||
ifneq ($(CPUFEATURES),yes)
|
||||
# need to be able to detect CPU features at runtime to enable any non-standard compiler flags
|
||||
STARCH_MIX := generic
|
||||
CPPFLAGS += -DSTARCH_MIX_GENERIC
|
||||
DUMP1090_CPPFLAGS += -DSTARCH_MIX_GENERIC
|
||||
else
|
||||
ifeq ($(ARCH),x86_64)
|
||||
# AVX, AVX2
|
||||
STARCH_MIX := x86
|
||||
CPPFLAGS += -DSTARCH_MIX_X86
|
||||
DUMP1090_CPPFLAGS += -DSTARCH_MIX_X86
|
||||
else ifeq ($(findstring aarch,$(ARCH)),aarch)
|
||||
STARCH_MIX := aarch64
|
||||
DUMP1090_CPPFLAGS += -DSTARCH_MIX_AARCH64
|
||||
else ifeq ($(findstring arm64,$(ARCH)),arm64)
|
||||
# Apple calls this arm64, not aarch64
|
||||
STARCH_MIX := aarch64
|
||||
DUMP1090_CPPFLAGS += -DSTARCH_MIX_AARCH64
|
||||
else ifeq ($(findstring arm,$(ARCH)),arm)
|
||||
# ARMv7 NEON
|
||||
STARCH_MIX := arm
|
||||
CPPFLAGS += -DSTARCH_MIX_ARM
|
||||
else ifeq ($(findstring aarch,$(ARCH)),aarch)
|
||||
STARCH_MIX := aarch64
|
||||
CPPFLAGS += -DSTARCH_MIX_AARCH64
|
||||
DUMP1090_CPPFLAGS += -DSTARCH_MIX_ARM
|
||||
else
|
||||
STARCH_MIX := generic
|
||||
CPPFLAGS += -DSTARCH_MIX_GENERIC
|
||||
DUMP1090_CPPFLAGS += -DSTARCH_MIX_GENERIC
|
||||
endif
|
||||
endif
|
||||
all: showconfig dump1090 view1090 starch-benchmark
|
||||
|
||||
STARCH_COMPILE := $(CC) $(CPPFLAGS) $(CFLAGS) -c
|
||||
ALL_CCFLAGS := $(CPPFLAGS) $(DUMP1090_CPPFLAGS) $(CFLAGS) $(DUMP1090_CFLAGS)
|
||||
|
||||
STARCH_COMPILE := $(CC) $(ALL_CCFLAGS) -c
|
||||
include dsp/generated/makefile.$(STARCH_MIX)
|
||||
|
||||
showconfig:
|
||||
@echo "Building with:" >&2
|
||||
@echo " Version string: $(DUMP1090_VERSION)" >&2
|
||||
@echo " Architecture: $(ARCH)" >&2
|
||||
@echo " DSP mix: $(STARCH_MIX)" >&2
|
||||
@echo " RTLSDR support: $(RTLSDR)" >&2
|
||||
@echo " BladeRF support: $(BLADERF)" >&2
|
||||
|
|
@ -184,15 +200,15 @@ showconfig:
|
|||
@echo " LimeSDR support: $(LIMESDR)" >&2
|
||||
|
||||
%.o: %.c *.h
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
|
||||
$(CC) $(ALL_CCFLAGS) -c $< -o $@
|
||||
|
||||
dump1090: dump1090.o anet.o interactive.o mode_ac.o mode_s.o comm_b.o net_io.o crc.o demod_2400.o stats.o cpr.o icao_filter.o track.o util.o convert.o ais_charset.o $(SDR_OBJ) $(COMPAT) $(CPUFEATURES_OBJS) $(STARCH_OBJS)
|
||||
dump1090: dump1090.o anet.o interactive.o mode_ac.o mode_s.o comm_b.o net_io.o crc.o demod_2400.o stats.o cpr.o icao_filter.o track.o util.o convert.o ais_charset.o adaptive.o $(SDR_OBJ) $(COMPAT) $(CPUFEATURES_OBJS) $(STARCH_OBJS)
|
||||
$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS) $(LIBS_SDR) $(LIBS_CURSES)
|
||||
|
||||
view1090: view1090.o anet.o interactive.o mode_ac.o mode_s.o comm_b.o net_io.o crc.o stats.o cpr.o icao_filter.o track.o util.o ais_charset.o $(COMPAT)
|
||||
view1090: view1090.o anet.o interactive.o mode_ac.o mode_s.o comm_b.o net_io.o crc.o stats.o cpr.o icao_filter.o track.o util.o ais_charset.o sdr_stub.o $(COMPAT)
|
||||
$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS) $(LIBS_CURSES)
|
||||
|
||||
faup1090: faup1090.o anet.o mode_ac.o mode_s.o comm_b.o net_io.o crc.o stats.o cpr.o icao_filter.o track.o util.o ais_charset.o $(COMPAT)
|
||||
faup1090: faup1090.o anet.o mode_ac.o mode_s.o comm_b.o net_io.o crc.o stats.o cpr.o icao_filter.o track.o util.o ais_charset.o sdr_stub.o $(COMPAT)
|
||||
$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS)
|
||||
|
||||
starch-benchmark: cpu.o dsp/helpers/tables.o $(CPUFEATURES_OBJS) $(STARCH_OBJS) $(STARCH_BENCHMARK_OBJ)
|
||||
|
|
@ -205,25 +221,25 @@ test: cprtests
|
|||
./cprtests
|
||||
|
||||
cprtests: cpr.o cprtests.o
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -g -o $@ $^ -lm
|
||||
$(CC) $(ALL_CCFLAGS) -g -o $@ $^ -lm
|
||||
|
||||
crctests: crc.c crc.h
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -g -DCRCDEBUG -o $@ $<
|
||||
$(CC) $(ALL_CCFLAGS) -g -DCRCDEBUG -o $@ $<
|
||||
|
||||
benchmarks: oneoff/convert_benchmark
|
||||
oneoff/convert_benchmark
|
||||
|
||||
oneoff/convert_benchmark: oneoff/convert_benchmark.o convert.o util.o dsp/helpers/tables.o cpu.o $(CPUFEATURES_OBJS) $(STARCH_OBJS)
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -g -o $@ $^ -lm -lpthread
|
||||
$(CC) $(ALL_CCFLAGS) -g -o $@ $^ -lm -lpthread
|
||||
|
||||
oneoff/decode_comm_b: oneoff/decode_comm_b.o comm_b.o ais_charset.o
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -g -o $@ $^ -lm
|
||||
$(CC) $(ALL_CCFLAGS) -g -o $@ $^ -lm
|
||||
|
||||
oneoff/dsp_error_measurement: oneoff/dsp_error_measurement.o dsp/helpers/tables.o cpu.o $(CPUFEATURES_OBJS) $(STARCH_OBJS)
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -g -o $@ $^ -lm
|
||||
$(CC) $(ALL_CCFLAGS) -g -o $@ $^ -lm
|
||||
|
||||
oneoff/uc8_capture_stats: oneoff/uc8_capture_stats.o
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -g -o $@ $^ -lm
|
||||
$(CC) $(ALL_CCFLAGS) -g -o $@ $^ -lm
|
||||
|
||||
starchgen:
|
||||
dsp/starchgen.py .
|
||||
|
|
|
|||
|
|
@ -2,22 +2,28 @@
|
|||
|
||||
# cmake integration is a little tricky, so let's do this by hand for now
|
||||
|
||||
CPUFEATURES_UNAME := $(shell uname)
|
||||
CPUFEATURES_ARCH := $(shell uname -m)
|
||||
CPUFEATURES_UNAME ?= $(UNAME)
|
||||
CPUFEATURES_ARCH ?= $(ARCH)
|
||||
CPUFEATURES_CFLAGS ?= $(CFLAGS)
|
||||
|
||||
CPUFEATURES_OBJS := cpu_features/src/filesystem.o cpu_features/src/stack_line_reader.o cpu_features/src/string_view.o
|
||||
CPUFEATURES_CFLAGS := -std=c99 -O -g -DSTACK_LINE_READER_BUFFER_SIZE=1024 -DNDEBUG
|
||||
CPUFEATURES_EXTRA_CFLAGS := -std=c99
|
||||
CPUFEATURES_EXTRA_CPPFLAGS := -DSTACK_LINE_READER_BUFFER_SIZE=1024 -DNDEBUG -Icpu_features/include
|
||||
|
||||
ifeq ($(CPUFEATURES_UNAME),Linux)
|
||||
CPUFEATURES_OBJS += cpu_features/src/hwcaps.o
|
||||
CPUFEATURES_CFLAGS += -DHAVE_STRONG_GETAUXVAL
|
||||
CPUFEATURES_EXTRA_CPPFLAGS += -DHAVE_STRONG_GETAUXVAL
|
||||
endif
|
||||
|
||||
ifeq ($(CPUFEATURES_UNAME),Darwin)
|
||||
CPUFEATURES_CFLAGS += -DHAVE_SYSCTLBYNAME
|
||||
CPUFEATURES_EXTRA_CPPFLAGS += -DHAVE_SYSCTLBYNAME
|
||||
endif
|
||||
|
||||
ifeq ($(CPUFEATURES_ARCH), x86_64)
|
||||
ifeq ($(CPUFEATURES_ARCH),x86_64)
|
||||
CPUFEATURES_OBJS += cpu_features/src/cpuinfo_x86.o
|
||||
endif
|
||||
|
||||
ifneq (,$(filter i%86,$(CPUFEATURES_ARCH)))
|
||||
CPUFEATURES_OBJS += cpu_features/src/cpuinfo_x86.o
|
||||
endif
|
||||
|
||||
|
|
@ -29,5 +35,4 @@ ifneq (,$(findstring aarch64,$(CPUFEATURES_ARCH)))
|
|||
CPUFEATURES_OBJS += cpu_features/src/cpuinfo_aarch64.o
|
||||
endif
|
||||
|
||||
$(CPUFEATURES_OBJS): override CFLAGS := $(CPUFEATURES_CFLAGS)
|
||||
$(CPUFEATURES_OBJS): override CPPFLAGS := -Icpu_features/include
|
||||
$(CPUFEATURES_OBJS): override ALL_CCFLAGS := $(CPUFEATURES_CPPFLAGS) $(CPUFEATURES_EXTRA_CPPFLAGS) $(CPUFEATURES_CFLAGS) $(CPUFEATURES_EXTRA_CFLAGS)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,191 @@
|
|||
# Adaptive gain configuration
|
||||
|
||||
dump1090-fa can optionally tune the receiver gain automatically to try to
|
||||
pick a gain value for the particular hardware and RF environment without
|
||||
manual tuning. This README covers some of the background for why this is
|
||||
useful, and how to configure dump1090 to enable this feature.
|
||||
|
||||
## Background
|
||||
|
||||
In general, more receiver gain means better reception. Most ADS-B transmitters
|
||||
within line of sight transmit with enough power that their messages can
|
||||
potentially be decoded, but if the receiver gain setting is too low then very
|
||||
weak signals may still be too weak to be decoded even after amplification.
|
||||
Adding extra receiver gain helps in this case.
|
||||
|
||||
However, there are two problems with just adding more gain to a wideband SDR.
|
||||
First, _everything_ is amplified, not only the signals of interest. Noise and
|
||||
RF interference is also amplified. At high gain settings or in noisy RF
|
||||
environments, this can interfere with receiving the ADS-B signals themselves.
|
||||
|
||||
Second, there is a wide range of possible ADS-B signal strengths. There can be
|
||||
a 60dB or more difference between the weakest signals (a distant aircraft at
|
||||
the limit of receiver range) and the strongest signals (a nearby aircraft on
|
||||
the ramp 100m from the receiver). Increasing the receiver gain to handle the
|
||||
weakest signals can mean that the strongest signals overload the receiver.
|
||||
A rtlsdr receiver only has about 30-35dB of dynamic range available at a
|
||||
particular gain setting, so there is no single gain setting that can
|
||||
simultaneously handle both the weakest and strongest signals.
|
||||
|
||||
Adaptive gain tries to deal with these cases by changing the receiver gain
|
||||
on the fly to handle the signal and noise levels that are currently being seen
|
||||
without human intervention. It is not perfect and it's not a substitute for
|
||||
hand-tuning of gain settings, but it aims at picking a reasonable setting for
|
||||
cases where individual hand-tuning isn't possible.
|
||||
|
||||
## Where to configure adaptive gain options
|
||||
|
||||
How to configure adaptive gain varies depending on how you have installed
|
||||
dump1090.
|
||||
|
||||
If you are using a PiAware sdcard image, adaptive gain can be configured by
|
||||
editing `/boot/piaware-config.txt` or by using the `piaware-config` command.
|
||||
|
||||
If you are using the Debian package, adaptive gain can be configured by editing
|
||||
`/etc/default/dump1090-fa`.
|
||||
|
||||
If running dump1090 directly, adaptive gain options are set directly by
|
||||
command-line options.
|
||||
|
||||
## Default settings
|
||||
|
||||
For new PiAware or Debian package installations, adaptive dynamic range mode
|
||||
is enabled by default and adaptive burst mode is disabled by default.
|
||||
|
||||
For _upgrades_ of PiAware or the Debian package from versions older than 6.0,
|
||||
both adaptive gain modes are disabled by default.
|
||||
|
||||
These defaults can be overridden as described below.
|
||||
|
||||
## Adaptive gain in dynamic range mode
|
||||
|
||||
The dynamic range adaptive gain mode attempts to set the receiver gain to
|
||||
maintain a given dynamic range - that is, it tries to set the gain so that
|
||||
general noise is at or below a given level. This takes into account different
|
||||
or changing RF environments and different receiver hardware (antenna,
|
||||
preamplifiers, etc) that affects the overall gain of the system, and usually
|
||||
will pick a reasonable gain setting without intervention.
|
||||
|
||||
To enable this mode:
|
||||
|
||||
* Set `adaptive-dynamic-range yes` in piaware-config; or
|
||||
* Set `ADAPTIVE_DYNAMIC_RANGE=yes` in `/etc/default/dump1090-fa`; or
|
||||
* Pass the `--adaptive-range` option on the command line.
|
||||
|
||||
The default settings for dynamic range will use a dynamic range target chosen
|
||||
based on SDR type (e.g. 30dB for rtlsdr receivers). This is usually a good
|
||||
default. To override this target:
|
||||
|
||||
* Set `adaptive-dynamic-range-target` in piaware-config; or
|
||||
* Set `ADAPTIVE_DYNAMIC_RANGE_TARGET` in `/etc/default/dump1090-fa`; or
|
||||
* Pass the `--adaptive-range-target` option on the command line.
|
||||
|
||||
## Adaptive gain in "burst" / loud signal mode
|
||||
|
||||
The "burst" adaptive gain mode listens for loud bursts of signal that were
|
||||
_not_ successfully decoded as ADS-B messages, but which have approximately
|
||||
the right timing to be possible messages that were lost due to receiver
|
||||
overloading. When enough overly-loud signals are heard in a short period of
|
||||
time, dump1090 will _reduce_ the receiver gain to try to allow them to be
|
||||
received.
|
||||
|
||||
This is a more situational setting. It may allow reception of loud nearby
|
||||
aircraft (e.g. if you are close to an airport). The tradeoff is that when
|
||||
there are nearby aircraft, overall receiver range may be reduced. Whether
|
||||
this is a good tradeoff depends on the aircraft you're interested in.
|
||||
By default, adaptive gain burst mode is disabled.
|
||||
|
||||
To enable burst mode:
|
||||
|
||||
* Set `adaptive-burst yes` in piaware-config; or
|
||||
* Set `ADAPTIVE_BURST=yes` in `/etc/default/dump1090-fa`; or
|
||||
* Pass the `--adaptive-burst` option on the command line.
|
||||
|
||||
This mode is more experimental than the dynamic range mode and tweaking of
|
||||
the advanced burst options may be needed depending on your local installation.
|
||||
In particular, `--adaptive-burst-loud-rate` and `adaptive-burst-quiet-rate`
|
||||
may need adjusting. Feedback on what works for you and what doesn't would
|
||||
be appreciated!
|
||||
|
||||
Burst mode and dynamic range mode can be enabled at the same time.
|
||||
|
||||
## Limiting the gain range
|
||||
|
||||
If you know in advance approximately what the gain setting should be, so
|
||||
you want to allow adaptive gain to change the gain only within a certain range,
|
||||
you can set minimum and maximum gain settings in dB. Adaptive gain will only
|
||||
adjust the gain within this range. To set this:
|
||||
|
||||
* Set `adaptive-min-gain` and `adaptive-max-gain` in piaware-config; or
|
||||
* Set `ADAPTIVE_MIN_GAIN` and `ADAPTIVE_MAX_GAIN` in `/etc/default/dump1090-fa`; or
|
||||
* Pass the `--adaptive-min-gain` and `--adaptive-max-gain` options on the command line.
|
||||
|
||||
If you know approximately where the gain should be, then a good starting point would be
|
||||
to set the max and min adaptive gain to +/- 10dB around your gain setting.
|
||||
|
||||
## Reducing the CPU cost of adaptive gain
|
||||
|
||||
The measurements needed to adjust gain have a CPU cost, and on slower
|
||||
devices it may be useful to reduce the amount of work that adaptive gain does.
|
||||
This can be done by adjusting the adaptive gain duty cycle. This is a
|
||||
percentage that controls what fraction of incoming data adaptive gain inspects.
|
||||
100% means that every sample is inspected. Lower values reduce CPU use, with
|
||||
a tradeoff that adaptive gain has a less accurate picture of the RF
|
||||
environment. The default duty cycle is 50% on "fast" CPUs and 10% on "slow"
|
||||
CPUs (where currently "slow" means "armv6 architecture", for example the
|
||||
Pi Zero or Pi 1). To reduce the duty cycle further:
|
||||
|
||||
* Set `slow-cpu yes` in piaware-config; or
|
||||
* Set `SLOW_CPU=yes` in `/etc/default/dump1090-fa`; or
|
||||
* Pass the `--adaptive-duty-cycle` option on the command line
|
||||
|
||||
## Advanced options
|
||||
|
||||
There are a number of advanced options that are only supported as
|
||||
command-line options or via the EXTRA_OPTIONS setting in
|
||||
`/etc/default/dump1090-fa`. They tweak settings that require some knowledge of
|
||||
dump1090 internals to make sense of, so YMMV.
|
||||
|
||||
For a complete list of options, run `dump1090-fa --help` and look at the
|
||||
adaptive gain section.
|
||||
|
||||
## Device support
|
||||
|
||||
Currently, adaptive gain is only supported on rtlsdr devices. Support for other
|
||||
SDRs is planned for the future.
|
||||
|
||||
If you're a developer and want to add support for your SDR, you'll need
|
||||
to implement the gain control API used in `sdr.[ch]`. See `sdr_rtlsdr.c`
|
||||
(`rtlsdrGetGain`, `rtlsdrSetGain`, etc) for examples.
|
||||
|
||||
## Comparison with wiedehopf's auto-gain scripts
|
||||
|
||||
There is an [auto-gain script](https://github.com/wiedehopf/adsb-scripts/wiki/Automatic-gain-optimization-for-readsb-and-dump1090-fa)
|
||||
written by [wiedehopf](https://github.com/wiedehopf) that aims to solve similar
|
||||
problems. The implementation approaches are quite different, and which one works best
|
||||
for you will depend on the problem you're trying to solve.
|
||||
|
||||
The major differences between adaptive gain and the auto-gain script are:
|
||||
|
||||
* Adaptive gain works on short-term data (seconds or minutes) and can react to
|
||||
changes in a similar timeframe. It tries to set an appropriate gain for the
|
||||
_current_ environment without much regard for longer-term trends. The auto-gain
|
||||
script looks at data over longer timeframes (1+ days) and reacts more slowly,
|
||||
but takes into account data across that whole period.
|
||||
|
||||
* Adaptive gain in dynamic range mode looks at an estimate of the noise floor
|
||||
to decide whether to increase gain. Adaptive gain in burst mode looks at the
|
||||
signal strength of samples that were _not_ successfully decoded to decide when
|
||||
to reduce gain. The auto-gain scripts look at the signal strength of _successfully_
|
||||
decoded messages to decide when to increase or decrease gain. These are each measuring
|
||||
something different, and which is most effective will depend on the exact RF
|
||||
environment.
|
||||
|
||||
* Adaptive gain burst mode and the auto-gain script superfically measure similar things,
|
||||
but the difference in measurement timeframe mean they react quite differently. Burst mode
|
||||
tries to react to transient loud signals i.e. temporarily nearby aircraft. The auto-gain
|
||||
script uses the loud-messages fraction as an estimate for messages lost to excessive
|
||||
gain over the long term, not only the transient case.
|
||||
|
||||
* Adaptive gain has a few less moving parts (i.e. no external scripts, no config changes over
|
||||
time) as it's built directly into dump1090 itself.
|
||||
54
README.md
54
README.md
|
|
@ -1,15 +1,3 @@
|
|||
# EOSS Specific Changes
|
||||
|
||||
The `eoss` branch adds the following changes/features so that the dump1090-fa release can work relatively seamlessly on the EOSS SDR system:
|
||||
- Updates to the web display and the underlying Javascript to Redirect the map source to the locally running OSM map server. This way map tiles are fetched from the local system and removes the need for a dedicated Internet connection.
|
||||
- Apache is used as the web server of choice instead of lighttpd. The Apache configuration is modified to use an alias (/dump1090-fa) pointing to the /user/share/dump1090-fa/html directory.
|
||||
- Parameter changes for the dump1090-fa daemon so that it looks to use only those RTL-SDR USB dongles that have been labeled with "ADSB" as their serial number. This allows
|
||||
multiple RTL-SDR dongles to be used on the SDR system (dump1090-fa uses one while the SDR system can use another).
|
||||
|
||||
For detailed instructions and build info for the `eoss` branch, please see the [EOSS-Install-dump1090](https://github.com/TheKoola/eosstracker/blob/master/doc/EOSS-Install-dump1090.md) under the eosstracker project.
|
||||
|
||||
|
||||
|
||||
# dump1090-fa Debian/Raspbian packages
|
||||
|
||||
dump1090-fa is a ADS-B, Mode S, and Mode 3A/3C demodulator and decoder that
|
||||
|
|
@ -28,49 +16,19 @@ it can be used to contribute crowd-sourced flight tracking data to FlightAware.
|
|||
It is designed to build as a Debian package, but should also be buildable on
|
||||
many other Linux or Unix-like systems.
|
||||
|
||||
## Building under buster
|
||||
## Building under bullseye, buster, or stretch
|
||||
|
||||
```bash
|
||||
$ sudo apt-get install build-essential fakeroot debhelper librtlsdr-dev pkg-config dh-systemd libncurses5-dev libbladerf-dev libhackrf-dev liblimesuite-dev
|
||||
$ sudo apt-get install build-essential fakeroot debhelper librtlsdr-dev pkg-config libncurses5-dev libbladerf-dev libhackrf-dev liblimesuite-dev
|
||||
$ ./prepare-build.sh bullseye # or buster, or stretch
|
||||
$ cd package-bullseye # or buster, or stretch
|
||||
$ dpkg-buildpackage -b --no-sign
|
||||
```
|
||||
|
||||
## Building under stretch
|
||||
|
||||
```bash
|
||||
$ sudo apt-get install build-essential debhelper librtlsdr-dev pkg-config dh-systemd libncurses5-dev libbladerf-dev
|
||||
$ dpkg-buildpackage -b --no-sign
|
||||
```
|
||||
|
||||
## Building under jessie
|
||||
|
||||
### Dependencies - bladeRF
|
||||
|
||||
You will need a build of libbladeRF. You can build packages from source:
|
||||
|
||||
```bash
|
||||
$ git clone https://github.com/Nuand/bladeRF.git
|
||||
$ cd bladeRF
|
||||
$ git checkout 2017.12-rc1
|
||||
$ dpkg-buildpackage -b
|
||||
```
|
||||
|
||||
Or Nuand has some build/install instructions including an Ubuntu PPA
|
||||
at https://github.com/Nuand/bladeRF/wiki/Getting-Started:-Linux
|
||||
|
||||
Or FlightAware provides armhf packages as part of the piaware repository;
|
||||
see https://flightaware.com/adsb/piaware/install
|
||||
|
||||
### Dependencies - rtlsdr
|
||||
|
||||
This is packaged with jessie. `sudo apt-get install librtlsdr-dev`
|
||||
|
||||
### Actually building it
|
||||
|
||||
Nothing special, just build it (`dpkg-buildpackage -b`)
|
||||
|
||||
## Building with limited dependencies
|
||||
|
||||
(Supported for bullseye and buster builds only)
|
||||
|
||||
The package supports some build profiles to allow building without all
|
||||
required SDR libraries being present. This will produce a package with
|
||||
limited SDR support only.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,645 @@
|
|||
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
|
||||
//
|
||||
// adaptive.c: adaptive gain control
|
||||
//
|
||||
// Copyright (c) 2021 FlightAware, LLC
|
||||
//
|
||||
// This file is free software: you may copy, redistribute and/or modify it
|
||||
// under the terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation, either version 2 of the License, or (at your
|
||||
// option) any later version.
|
||||
//
|
||||
// This file is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "dump1090.h"
|
||||
#include "adaptive.h"
|
||||
|
||||
//
|
||||
// gain limits
|
||||
//
|
||||
static int adaptive_gain_min;
|
||||
static int adaptive_gain_max;
|
||||
|
||||
// gain steps relative to current gain
|
||||
static float adaptive_gain_up_db;
|
||||
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 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_subblock(uint16_t *buf, unsigned length, struct modesMessage *decoded);
|
||||
static void adaptive_end_of_block();
|
||||
static void adaptive_control_update();
|
||||
|
||||
//
|
||||
// burst handling
|
||||
//
|
||||
|
||||
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
|
||||
static unsigned adaptive_burst_block_loud_undecoded; // loud undecoded bursts seen in this block so far
|
||||
static unsigned adaptive_burst_block_loud_decoded; // loud decoded messages seen in this block so far
|
||||
static double adaptive_burst_loud_undecoded_smoothed; // smoothed rate of loud misdecodes per block
|
||||
static double adaptive_burst_loud_decoded_smoothed; // smoothed rate of loud successful decodes per block
|
||||
static unsigned adaptive_burst_change_timer; // countdown inhibiting control after changing gain
|
||||
static double adaptive_burst_loud_threshold; // current signal level threshold for a "loud decode"
|
||||
static unsigned adaptive_burst_loud_blocks = 0; // consecutive blocks with loud rate
|
||||
static unsigned adaptive_burst_quiet_blocks = 0; // consecutive blocks with quiet rate
|
||||
|
||||
static void adaptive_burst_update(uint16_t *buf, unsigned length);
|
||||
static void adaptive_burst_skip(unsigned length);
|
||||
static unsigned adaptive_burst_count_samples(uint16_t *buf, unsigned n);
|
||||
static void adaptive_burst_scan_windows(uint16_t *buf, unsigned windows);
|
||||
static void adaptive_burst_end_of_window(unsigned counter);
|
||||
static void adaptive_burst_end_of_block();
|
||||
|
||||
//
|
||||
// noise floor measurement (adaptive dynamic range)
|
||||
//
|
||||
|
||||
static unsigned *adaptive_range_radix; // radix-sort buckets for current block
|
||||
static unsigned adaptive_range_radix_counter; // sum of all radix-sort buckets (= number of samples sorted)
|
||||
static double adaptive_range_smoothed; // smoothed noise floor estimate, dBFS
|
||||
static enum { RANGE_SCAN_IDLE, RANGE_SCAN_UP, RANGE_SCAN_DOWN, RANGE_RESCAN_UP, RANGE_RESCAN_DOWN } adaptive_range_state = RANGE_SCAN_UP;
|
||||
static unsigned adaptive_range_change_timer; // countdown inhibiting control after changing gain
|
||||
static unsigned adaptive_range_rescan_timer; // countdown to next upwards gain reprobe
|
||||
static int adaptive_range_gain_limit; // probed maximum gain step with acceptable dynamic range
|
||||
|
||||
static void adaptive_range_update(uint16_t *buf, unsigned length);
|
||||
static void adaptive_range_end_of_block();
|
||||
|
||||
// Try to change the SDR gain to 'step' and tell the user about it,
|
||||
// with 'why' as the reason to show. Return true if the gain actually changed.
|
||||
static bool adaptive_set_gain(int step, const char *why)
|
||||
{
|
||||
if (step < adaptive_gain_min)
|
||||
step = adaptive_gain_min;
|
||||
if (step > adaptive_gain_max)
|
||||
step = adaptive_gain_max;
|
||||
|
||||
int current_gain = sdrGetGain();
|
||||
if (current_gain == step)
|
||||
return false;
|
||||
|
||||
fprintf(stderr, "adaptive: changing gain from %.1fdB (step %d) to %.1fdB (step %d) because: %s\n",
|
||||
sdrGetGainDb(current_gain), current_gain, sdrGetGainDb(step), step, why);
|
||||
|
||||
int new_gain = sdrSetGain(step);
|
||||
bool changed = (current_gain != new_gain);
|
||||
if (changed)
|
||||
++Modes.stats_current.adaptive_gain_changes;
|
||||
return changed;
|
||||
}
|
||||
|
||||
// Update internal state to reflect a gain change
|
||||
// (usually after adaptive_set_gain returns true, but also called during init)
|
||||
static void adaptive_gain_changed()
|
||||
{
|
||||
int new_gain = sdrGetGain();
|
||||
adaptive_gain_up_db = sdrGetGainDb(new_gain + 1) - sdrGetGainDb(new_gain);
|
||||
adaptive_gain_down_db = sdrGetGainDb(new_gain) - sdrGetGainDb(new_gain - 1);
|
||||
|
||||
double loud_threshold_dbfs = 0 - adaptive_gain_up_db - 3.0;
|
||||
adaptive_burst_loud_threshold = pow(10, loud_threshold_dbfs / 10.0);
|
||||
|
||||
adaptive_range_change_timer = Modes.adaptive_range_change_delay;
|
||||
adaptive_burst_change_timer = Modes.adaptive_burst_change_delay;
|
||||
adaptive_burst_loud_blocks = 0;
|
||||
adaptive_burst_quiet_blocks = 0;
|
||||
}
|
||||
|
||||
// External init entry point
|
||||
void adaptive_init()
|
||||
{
|
||||
int maxgain = sdrGetMaxGain();
|
||||
|
||||
// If the SDR doesn't support gain control, disable ourselves
|
||||
if (maxgain < 0) {
|
||||
if (Modes.adaptive_burst_control || Modes.adaptive_range_control) {
|
||||
fprintf(stderr, "warning: adaptive gain control requested, but SDR gain control not available, ignored.\n");
|
||||
}
|
||||
Modes.adaptive_burst_control = false;
|
||||
Modes.adaptive_range_control = false;
|
||||
}
|
||||
|
||||
// If we're disabled, do nothing
|
||||
if (!Modes.adaptive_burst_control && !Modes.adaptive_range_control)
|
||||
return;
|
||||
|
||||
// Set up window, subblock, and block sizes
|
||||
// Look for 40us bursts
|
||||
adaptive_samples_per_window = Modes.sample_rate / 25000;
|
||||
|
||||
// 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_RESCAN_UP;
|
||||
|
||||
// select and enforce gain limits
|
||||
for (adaptive_gain_min = 0; adaptive_gain_min < maxgain; ++adaptive_gain_min) {
|
||||
if (sdrGetGainDb(adaptive_gain_min) >= Modes.adaptive_min_gain_db)
|
||||
break;
|
||||
}
|
||||
|
||||
for (adaptive_gain_max = maxgain; adaptive_gain_max > adaptive_gain_min; --adaptive_gain_max) {
|
||||
if (sdrGetGainDb(adaptive_gain_max) <= Modes.adaptive_max_gain_db)
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(stderr, "adaptive: enabled adaptive gain control with gain limits %.1fdB (step %d) .. %.1fdB (step %d)\n",
|
||||
sdrGetGainDb(adaptive_gain_min), adaptive_gain_min, sdrGetGainDb(adaptive_gain_max), adaptive_gain_max);
|
||||
if (Modes.adaptive_range_control)
|
||||
fprintf(stderr, "adaptive: enabled dynamic range control, target dynamic range %.1fdB\n", Modes.adaptive_range_target);
|
||||
if (Modes.adaptive_burst_control)
|
||||
fprintf(stderr, "adaptive: enabled burst control\n");
|
||||
adaptive_set_gain(sdrGetGain(), "constraining gain to adaptive gain limits");
|
||||
adaptive_gain_changed();
|
||||
|
||||
adaptive_range_gain_limit = sdrGetGain();
|
||||
}
|
||||
|
||||
// Feed some samples into the adaptive system. Any number of samples might be passed in.
|
||||
void adaptive_update(uint16_t *buf, unsigned length, struct modesMessage *decoded)
|
||||
{
|
||||
if (!Modes.adaptive_burst_control && !Modes.adaptive_range_control)
|
||||
return;
|
||||
|
||||
// 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 subblock
|
||||
if (length > 0) {
|
||||
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 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)
|
||||
++adaptive_burst_block_loud_decoded;
|
||||
adaptive_burst_skip(length);
|
||||
} else {
|
||||
adaptive_burst_update(buf, length);
|
||||
adaptive_range_update(buf, length);
|
||||
}
|
||||
}
|
||||
|
||||
// Burst measurement: ignore the next 'length' samples (they are a successfully decoded message)
|
||||
static void adaptive_burst_skip(unsigned length)
|
||||
{
|
||||
if (!Modes.adaptive_burst_control)
|
||||
return;
|
||||
|
||||
// first window
|
||||
if (length < adaptive_burst_window_remaining) {
|
||||
// partial fill
|
||||
adaptive_burst_window_remaining -= length;
|
||||
return;
|
||||
}
|
||||
|
||||
// skip remainder of first window, dispatch it
|
||||
adaptive_burst_end_of_window(adaptive_burst_window_counter);
|
||||
length -= adaptive_burst_window_remaining;
|
||||
|
||||
// skip remaining windows, dispatch them
|
||||
unsigned windows = length / adaptive_samples_per_window;
|
||||
unsigned samples = windows * adaptive_samples_per_window;
|
||||
while (windows--)
|
||||
adaptive_burst_end_of_window(0);
|
||||
|
||||
length -= samples;
|
||||
|
||||
// final partial window
|
||||
adaptive_burst_window_counter = 0;
|
||||
adaptive_burst_window_remaining = adaptive_samples_per_window - length;
|
||||
}
|
||||
|
||||
// Burst measurement: process 'length' samples from 'buf', look for loud bursts;
|
||||
// the samples might cross burst window boundaries;
|
||||
// the samples will not cross a block boundary.
|
||||
static void adaptive_burst_update(uint16_t *buf, unsigned length)
|
||||
{
|
||||
if (!Modes.adaptive_burst_control)
|
||||
return;
|
||||
|
||||
// first window
|
||||
if (length < adaptive_burst_window_remaining) {
|
||||
// partial fill
|
||||
adaptive_burst_window_counter += adaptive_burst_count_samples(buf, length);
|
||||
adaptive_burst_window_remaining -= length;
|
||||
return;
|
||||
}
|
||||
|
||||
// complete fill of first partial window
|
||||
unsigned n = adaptive_burst_window_remaining;
|
||||
unsigned counter = adaptive_burst_window_counter + adaptive_burst_count_samples(buf, n);
|
||||
adaptive_burst_end_of_window(counter);
|
||||
buf += n;
|
||||
length -= n;
|
||||
|
||||
// remaining windows
|
||||
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_samples_per_window - length;
|
||||
}
|
||||
|
||||
// Burst measurement: process 'windows' complete burst windows starting at 'buf';
|
||||
// 'buf' is aligned to the start of a burst window
|
||||
static void adaptive_burst_scan_windows(uint16_t *buf, unsigned windows)
|
||||
{
|
||||
while (windows--) {
|
||||
unsigned counter = adaptive_burst_count_samples(buf, adaptive_samples_per_window);
|
||||
buf += adaptive_samples_per_window;
|
||||
adaptive_burst_end_of_window(counter);
|
||||
}
|
||||
}
|
||||
|
||||
// Burst measurement: process 'n' samples from 'buf', look for loud samples;
|
||||
// the samples are guaranteed not to cross window boundaries;
|
||||
// return the number of loud samples seen
|
||||
static inline unsigned adaptive_burst_count_samples(uint16_t *buf, unsigned n)
|
||||
{
|
||||
unsigned counter;
|
||||
starch_count_above_u16(buf, n, 46395 /* -3dBFS */, &counter);
|
||||
return counter;
|
||||
}
|
||||
|
||||
// Burst measurement: we reached the end of a burst window with 'counter'
|
||||
// loud samples seen, handle that window.
|
||||
static void adaptive_burst_end_of_window(unsigned counter)
|
||||
{
|
||||
if (counter > adaptive_samples_per_window / 4) {
|
||||
// This window is loud, extend any existing run of loud windows
|
||||
++adaptive_burst_runlength;
|
||||
} else {
|
||||
// Quiet window. If we saw a run of loud windows >= 80us long, count
|
||||
// that as a candidate for an over-amplified message that was
|
||||
// not decoded.
|
||||
if (adaptive_burst_runlength >= 2 && adaptive_burst_runlength <= 5)
|
||||
++adaptive_burst_block_loud_undecoded;
|
||||
adaptive_burst_runlength = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Noise measurement: process 'length' samples from 'buf'.
|
||||
// The samples will not cross a block boundary.
|
||||
static void adaptive_range_update(uint16_t *buf, unsigned length)
|
||||
{
|
||||
if (!Modes.adaptive_range_control)
|
||||
return;
|
||||
|
||||
adaptive_range_radix_counter += length;
|
||||
while (length--) {
|
||||
// do a very simple radix sort of sample magnitudes
|
||||
// so we can later find the Nth percentile value
|
||||
++adaptive_range_radix[buf[0]];
|
||||
++buf;
|
||||
}
|
||||
}
|
||||
|
||||
// Noise measurement: we reached the end of a block, update
|
||||
// our noise estimate
|
||||
static void adaptive_range_end_of_block()
|
||||
{
|
||||
if (!Modes.adaptive_range_control)
|
||||
return;
|
||||
|
||||
unsigned n = 0, i = 0;
|
||||
|
||||
// measure Nth percentile magnitude
|
||||
unsigned count_n = adaptive_range_radix_counter * Modes.adaptive_range_percentile / 100;
|
||||
while (i < 65536 && n <= count_n)
|
||||
n += adaptive_range_radix[i++];
|
||||
uint16_t percentile_n = i - 1;
|
||||
|
||||
// maintain an EMA of the Nth percentile
|
||||
adaptive_range_smoothed = adaptive_range_smoothed * (1 - Modes.adaptive_range_alpha) + percentile_n * Modes.adaptive_range_alpha;
|
||||
// .. report to stats in dBFS
|
||||
if (adaptive_range_smoothed > 0) {
|
||||
Modes.stats_current.adaptive_noise_dbfs = 20 * log10(adaptive_range_smoothed / 65536.0);
|
||||
} else {
|
||||
Modes.stats_current.adaptive_noise_dbfs = 0;
|
||||
}
|
||||
|
||||
// reset radix sort for the next block
|
||||
memset(adaptive_range_radix, 0, 65536 * sizeof(unsigned));
|
||||
adaptive_range_radix_counter = 0;
|
||||
}
|
||||
|
||||
// Burst measurement: we reached the end of a block, update our burst rate estimate
|
||||
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) + 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) + scale * adaptive_burst_block_loud_decoded * Modes.adaptive_burst_alpha;
|
||||
adaptive_burst_block_loud_decoded = 0;
|
||||
}
|
||||
|
||||
|
||||
void flush_stats(uint64_t now);
|
||||
|
||||
static void adaptive_increase_gain(const char *why)
|
||||
{
|
||||
if (adaptive_set_gain(sdrGetGain() + 1, why))
|
||||
adaptive_gain_changed();
|
||||
}
|
||||
|
||||
static void adaptive_decrease_gain(const char *why)
|
||||
{
|
||||
if (adaptive_set_gain(sdrGetGain() - 1, why))
|
||||
adaptive_gain_changed();
|
||||
}
|
||||
|
||||
// Adaptive gain: we reached a block boundary. Update measurements and act on them.
|
||||
static void adaptive_end_of_block()
|
||||
{
|
||||
adaptive_range_end_of_block();
|
||||
adaptive_burst_end_of_block();
|
||||
|
||||
adaptive_control_update();
|
||||
|
||||
Modes.stats_current.adaptive_valid = true;
|
||||
unsigned current = Modes.stats_current.adaptive_gain = sdrGetGain();
|
||||
Modes.stats_current.adaptive_range_gain_limit = adaptive_range_gain_limit;
|
||||
++Modes.stats_current.adaptive_gain_seconds[current < STATS_GAIN_COUNT ? current : STATS_GAIN_COUNT-1];
|
||||
}
|
||||
|
||||
static void adaptive_control_update()
|
||||
{
|
||||
// votes for what to do with the gain
|
||||
// "gain_not_up" overlaps somewhat with "gain_down", but they are not identical;
|
||||
// burst control may want to prevent gain from increasing, but not necessarily
|
||||
// decrease gain.
|
||||
|
||||
bool gain_up = false;
|
||||
const char *gain_up_reason = NULL;
|
||||
bool gain_down = false;
|
||||
const char *gain_down_reason = NULL;
|
||||
bool gain_not_up = false;
|
||||
|
||||
int current_gain = sdrGetGain();
|
||||
|
||||
if (adaptive_burst_change_timer)
|
||||
--adaptive_burst_change_timer;
|
||||
if (adaptive_range_change_timer > 0)
|
||||
--adaptive_range_change_timer;
|
||||
if (adaptive_range_rescan_timer > 0)
|
||||
--adaptive_range_rescan_timer;
|
||||
|
||||
if (Modes.adaptive_burst_control && !adaptive_burst_change_timer) {
|
||||
if (adaptive_burst_loud_undecoded_smoothed > Modes.adaptive_burst_loud_rate) {
|
||||
adaptive_burst_quiet_blocks = 0;
|
||||
++adaptive_burst_loud_blocks;
|
||||
} else if (adaptive_burst_loud_decoded_smoothed < Modes.adaptive_burst_quiet_rate) {
|
||||
adaptive_burst_loud_blocks = 0;
|
||||
++adaptive_burst_quiet_blocks;
|
||||
} else {
|
||||
adaptive_burst_loud_blocks = 0;
|
||||
adaptive_burst_quiet_blocks = 0;
|
||||
}
|
||||
|
||||
if (adaptive_burst_loud_blocks >= Modes.adaptive_burst_loud_runlength) {
|
||||
// we need to reduce gain (further)
|
||||
gain_down = gain_not_up = true;
|
||||
gain_down_reason = "high rate of loud undecoded messages";
|
||||
|
||||
// if we're currently doing a downward scan, reducing gain further may confuse it;
|
||||
// stop that scan and restart it once we are no longer in a reduced-gain state
|
||||
if (adaptive_range_state == RANGE_SCAN_DOWN || adaptive_range_state == RANGE_RESCAN_DOWN) {
|
||||
adaptive_range_state = RANGE_SCAN_IDLE;
|
||||
adaptive_range_rescan_timer = 0;
|
||||
}
|
||||
} else if (adaptive_burst_quiet_blocks < Modes.adaptive_burst_quiet_runlength) {
|
||||
// we're OK at the current gain, but should not increase it
|
||||
gain_not_up = true;
|
||||
} else if (current_gain < adaptive_range_gain_limit) {
|
||||
// we're OK at the current gain, and can increase gain to the previously discovered
|
||||
// dynamic range limit
|
||||
gain_up = true;
|
||||
gain_up_reason = "low loud message rate and gain below dynamic range limit";
|
||||
}
|
||||
}
|
||||
|
||||
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 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:
|
||||
case RANGE_RESCAN_UP:
|
||||
if (available_range < Modes.adaptive_range_target) {
|
||||
// Current gain fails to meet our target. Switch to downward scanning.
|
||||
fprintf(stderr, "adaptive: available dynamic range (%.1fdB) < required dynamic range (%.1fdB), switching to downward scan\n", available_range, Modes.adaptive_range_target);
|
||||
gain_down = gain_not_up = true;
|
||||
gain_down_reason = "probing dynamic range gain lower bound";
|
||||
adaptive_range_state = (adaptive_range_state == RANGE_RESCAN_UP ? RANGE_RESCAN_DOWN : RANGE_SCAN_DOWN);
|
||||
if (adaptive_range_gain_limit >= current_gain) {
|
||||
adaptive_range_gain_limit = current_gain - 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (sdrGetGain() >= adaptive_gain_max) {
|
||||
// We have reached our upper gain limit
|
||||
fprintf(stderr, "adaptive: reached upper gain limit, halting dynamic range scan here\n");
|
||||
adaptive_range_state = RANGE_SCAN_IDLE;
|
||||
adaptive_range_rescan_timer = Modes.adaptive_range_rescan_delay;
|
||||
break;
|
||||
}
|
||||
|
||||
// This gain step is OK and we have more to try, try the next gain step up.
|
||||
// (But if burst detection has inhibited increasing gain, don't do anything yet, just try again next block)
|
||||
if (!gain_not_up) {
|
||||
fprintf(stderr, "adaptive: available dynamic range (%.1fdB) >= required dynamic range (%.1fdB), continuing upward scan\n", available_range, Modes.adaptive_range_target);
|
||||
gain_up = true;
|
||||
gain_up_reason = "probing dynamic range gain upper bound";
|
||||
}
|
||||
break;
|
||||
|
||||
case RANGE_SCAN_DOWN:
|
||||
case RANGE_RESCAN_DOWN:
|
||||
if (available_range >= Modes.adaptive_range_target) {
|
||||
// Current gain meets our target; we are done with the scan.
|
||||
fprintf(stderr, "adaptive: available dynamic range (%.1fdB) >= required dynamic range (%.1fdB), stopping downwards scan here\n", available_range, Modes.adaptive_range_target);
|
||||
adaptive_range_state = RANGE_SCAN_IDLE;
|
||||
adaptive_range_rescan_timer = (adaptive_range_state == RANGE_SCAN_DOWN ? Modes.adaptive_range_scan_delay : Modes.adaptive_range_rescan_delay);
|
||||
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;
|
||||
adaptive_range_rescan_timer = Modes.adaptive_range_rescan_delay;
|
||||
break;
|
||||
}
|
||||
|
||||
// This gain step is too loud and we have more to try, try the next gain step down
|
||||
fprintf(stderr, "adaptive: available dynamic range (%.1fdB) < required dynamic range (%.1fdB), continuing downwards scan\n", available_range, Modes.adaptive_range_target);
|
||||
gain_down = gain_not_up = true;
|
||||
gain_down_reason = "probing dynamic range gain lower bound";
|
||||
break;
|
||||
|
||||
case RANGE_SCAN_IDLE:
|
||||
// Look for increased noise that could be compensated for by decreasing gain.
|
||||
// Do this even if we're waiting to rescan or if burst control is also active
|
||||
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 (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";
|
||||
break;
|
||||
}
|
||||
|
||||
// Infrequently consider increasing gain to handle the case where we've selected a too-low gain where the noise floor is dominated by noise unrelated to the gain setting.
|
||||
// But don't do this while burst control is preventing gain increases.
|
||||
if (!adaptive_range_rescan_timer && !gain_not_up) {
|
||||
if (available_range >= Modes.adaptive_range_target && sdrGetGain() < adaptive_gain_max) {
|
||||
fprintf(stderr, "adaptive: start periodic scan for acceptable dynamic range at increased gain\n");
|
||||
gain_up = true;
|
||||
gain_up_reason = "periodic re-probing of dynamic range gain upper bound";
|
||||
adaptive_range_state = RANGE_RESCAN_UP;
|
||||
break;
|
||||
}
|
||||
|
||||
// Nothing to do for a while.
|
||||
adaptive_range_rescan_timer = Modes.adaptive_range_rescan_delay;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "adaptive: in a weird state (%d), trying to fix it\n", adaptive_range_state);
|
||||
adaptive_range_state = RANGE_SCAN_IDLE;
|
||||
adaptive_range_rescan_timer = Modes.adaptive_range_rescan_delay;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// now actually perform any gain changes
|
||||
|
||||
if (gain_down)
|
||||
adaptive_decrease_gain(gain_down_reason);
|
||||
else if (gain_up && !gain_not_up)
|
||||
adaptive_increase_gain(gain_up_reason);
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
|
||||
//
|
||||
// adaptive.h: adaptive gain control prototypes
|
||||
//
|
||||
// Copyright (c) 2021 FlightAware, LLC
|
||||
//
|
||||
// This file is free software: you may copy, redistribute and/or modify it
|
||||
// under the terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation, either version 2 of the License, or (at your
|
||||
// option) any later version.
|
||||
//
|
||||
// This file is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef ADAPTIVE_H
|
||||
#define ADAPTIVE_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
struct modesMessage;
|
||||
|
||||
void adaptive_init();
|
||||
void adaptive_update(uint16_t *buf, unsigned length, struct modesMessage *decoded);
|
||||
|
||||
#endif
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
Source: dump1090-fa
|
||||
Section: embedded
|
||||
Priority: extra
|
||||
Maintainer: Oliver Jowett <oliver@mutability.co.uk>
|
||||
Build-Depends: debhelper(>=9), librtlsdr-dev, libusb-1.0-0-dev, pkg-config, dh-systemd, libncurses5-dev, libbladerf-dev
|
||||
Standards-Version: 3.9.3
|
||||
Homepage: http://www.flightaware.com/
|
||||
Vcs-Git: https://github.com/flightaware/dump1090.git
|
||||
|
||||
Package: dump1090
|
||||
Architecture: all
|
||||
Depends: dump1090-fa, ${misc:Depends}
|
||||
Priority: extra
|
||||
Section: oldlibs
|
||||
Description: transitional dummy package for dump1090
|
||||
This is a transitional dummy package to handle upgrades from
|
||||
the old package name of "dump1090" to the new package name of
|
||||
"dump1090-fa". It can safely be removed.
|
||||
|
||||
Package: dump1090-fa
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, libbladerf1 (>= 0.2016.06), adduser, lighttpd
|
||||
Replaces: dump1090 (<< 3.0)
|
||||
Breaks: dump1090 (<< 3.0)
|
||||
Description: ADS-B Ground Station System for RTL-SDR
|
||||
Networked Aviation Mode S / ADS-B decoder/translator with RTL-SDR software
|
||||
defined radio USB device support.
|
||||
.
|
||||
This is FlightAware's fork of dump1090-mutability, customized for use
|
||||
in the PiAware sdcard images.
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
#!/usr/bin/make -f
|
||||
# -*- makefile -*-
|
||||
# Sample debian/rules that uses debhelper.
|
||||
# This file was originally written by Joey Hess and Craig Small.
|
||||
# As a special exception, when this file is copied by dh-make into a
|
||||
# dh-make output file, you may use that output file without restriction.
|
||||
# This special exception was added by Craig Small in version 0.37 of dh-make.
|
||||
|
||||
# Uncomment this to turn on verbose mode.
|
||||
export DH_VERBOSE=1
|
||||
|
||||
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
||||
|
||||
DPKG_EXPORT_BUILDFLAGS = 1
|
||||
include /usr/share/dpkg/default.mk
|
||||
|
||||
override_dh_auto_build:
|
||||
# jessie's gcc doesn't support the compiler flags needed for ARM-specific starch flavors;
|
||||
# turn off runtime CPU detection
|
||||
dh_auto_build -- RTLSDR=yes BLADERF=yes HACKRF=no LIMESDR=no DUMP1090_VERSION=$(DEB_VERSION) CPUFEATURES=no
|
||||
|
||||
override_dh_install:
|
||||
dh_install
|
||||
install -d debian/dump1090-fa/usr/bin
|
||||
cp -a dump1090 debian/dump1090-fa/usr/bin/dump1090-fa
|
||||
cp -a view1090 debian/dump1090-fa/usr/bin/view1090-fa
|
||||
|
||||
%:
|
||||
dh $@ --with=systemd
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
Source: dump1090-fa
|
||||
Section: embedded
|
||||
Priority: extra
|
||||
Maintainer: Oliver Jowett <oliver@mutability.co.uk>
|
||||
Build-Depends: debhelper(>=9), librtlsdr-dev, libusb-1.0-0-dev, pkg-config, dh-systemd, libncurses5-dev, libbladerf-dev
|
||||
Maintainer: Oliver Jowett <oliver.jowett@flightaware.com>
|
||||
Build-Depends: debhelper(>=10), librtlsdr-dev, libusb-1.0-0-dev, pkg-config, libncurses5-dev, libbladerf-dev
|
||||
Standards-Version: 3.9.3
|
||||
Homepage: http://www.flightaware.com/
|
||||
Vcs-Git: https://github.com/flightaware/dump1090.git
|
||||
|
|
|
|||
|
|
@ -25,5 +25,11 @@ override_dh_install:
|
|||
cp -a dump1090 debian/dump1090-fa/usr/bin/dump1090-fa
|
||||
cp -a view1090 debian/dump1090-fa/usr/bin/view1090-fa
|
||||
|
||||
override_dh_installinit:
|
||||
dh_installinit --no-stop-on-upgrade --no-restart-after-upgrade
|
||||
|
||||
override_dh_systemd_start:
|
||||
dh_systemd_start --no-stop-on-upgrade --no-restart-after-upgrade --name=dump1090-fa.service
|
||||
|
||||
%:
|
||||
dh $@ --with=systemd
|
||||
|
|
|
|||
|
|
@ -1,3 +1,52 @@
|
|||
dump1090-fa (7.2) stable; urgency=medium
|
||||
|
||||
* dump1090: Fix Makefile syntax error for Darwin OS build (courtesy @CodyCodeman, PR #170)
|
||||
* dump1090: set _POSIX_C_SOURCE to fix build failure with uclibc-ng (courtesy @ffontaine, PR #169)
|
||||
* SkyAware: Remove obselete map interface at /dump1090-fa
|
||||
* SkyAware: Remove OSM Black & White layer which is no longer in service
|
||||
|
||||
-- Eric Tran <eric.tran@flightaware.com> Wed, 09 Mar 2022 20:09:55 -0600
|
||||
|
||||
dump1090-fa (7.1) stable; urgency=medium
|
||||
|
||||
* Preserve start/upgrade postinst logic for pre 7.1 updates until we support compat 10 behavior
|
||||
|
||||
-- Eric Tran <eric.tran@flightaware.com> Wed, 12 Jan 2022 11:37:20 -0600
|
||||
|
||||
dump1090-fa (7.0) stable; urgency=medium
|
||||
|
||||
* dump1090: Allow env vars (not only command line overrdies) to set CPU_FEATURES_{ARCH,UNAME}
|
||||
* dump1090: Treat ARCH=arm64 like ARCH=aarch64
|
||||
* dump1090: Try to respect CFLAGS/CPPFLAGS as far as possible; move required extra flags into a separate var
|
||||
* dump1090: Adaptive gain - more aggressively re-probe for higher gain after a decrease in gain due to increased noise floor
|
||||
* dump1090: Cleanup AVR parsing
|
||||
* SkyAware: Update aircraft db to 20211210
|
||||
* SkyAware: Cleanup unused Openlayers files
|
||||
|
||||
-- Eric Tran <eric.tran@flightaware.com> Mon, 20 Dec 2021 11:00:00 -0600
|
||||
|
||||
dump1090-fa (6.1) stable; urgency=medium
|
||||
|
||||
* No-change 6.1 release for PiAware 6.1
|
||||
|
||||
-- Oliver Jowett <oliver.jowett@flightaware.com> Mon, 06 Sep 2021 16:06:00 +0800
|
||||
|
||||
dump1090-fa (6.0) stable; urgency=medium
|
||||
|
||||
* dump1090: Adaptive gain feature with associated dump1090-fa config parameters
|
||||
* dump1090: Add support for decoding BDS 4,4 - Meteorological Routine Air Report (MRAR) Comm-B messages
|
||||
* dump1090: Stratux output: include current receiver gain (courtesy @b3nn0, PR #144)
|
||||
* dump1090: Enable rtlsdr bounce buffers on aarch64 (courtesy @wiedehopf for suggestion)
|
||||
* dump1090: New default dump1090-fa config file format
|
||||
* dump1090: Use compat/compat.h for endian-swapping functions in DSP code
|
||||
* dump1090: Report json write errors, with some rate limiting (fixes issue #129)
|
||||
* starch: Update starch to upstream commit 0c8249fa4bc523345c156885542e9192e8bf68fd
|
||||
* SkyAware: restrict overlay rendering to covered areas (reduce source load) (courtesy @wiedehopf, PR #137)
|
||||
* SkyAware: Fix ignored DisplayUnits in config.js (courtesy @paulyc, PR #76)
|
||||
* SkyAware: Update aircraft db to 20210817 with better Australian aircraft & types
|
||||
|
||||
-- Eric Tran <eric.tran@flightaware.com> Tue, 31 Aug 2021 12:41:06 -0600
|
||||
|
||||
dump1090-fa (5.0) stable; urgency=medium
|
||||
|
||||
* SkyAware: New Altitude, Speed, Aircraft Ident, and Aircraft Type filters to fine tune the select aircraft you want see
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
9
|
||||
10
|
||||
|
|
|
|||
|
|
@ -2,30 +2,20 @@ Source: dump1090-fa
|
|||
Section: embedded
|
||||
Priority: extra
|
||||
Maintainer: Oliver Jowett <oliver.jowett@flightaware.com>
|
||||
Build-Depends: debhelper(>=9),
|
||||
Build-Depends: debhelper(>=10),
|
||||
librtlsdr-dev <!custom> <rtlsdr>,
|
||||
libbladerf-dev <!custom> <bladerf>,
|
||||
libhackrf-dev <!custom> <hackrf>,
|
||||
liblimesuite-dev <!custom> <limesdr>,
|
||||
libusb-1.0-0-dev <!custom> <rtlsdr> <bladerf> <hackrf> <limesdr>,
|
||||
pkg-config, dh-systemd, libncurses5-dev
|
||||
pkg-config, libncurses5-dev
|
||||
Standards-Version: 3.9.3
|
||||
Homepage: http://www.flightaware.com/
|
||||
Vcs-Git: https://github.com/edgeofspace/dump1090-fa.git
|
||||
|
||||
Package: dump1090
|
||||
Architecture: all
|
||||
Depends: dump1090-fa, ${misc:Depends}
|
||||
Priority: extra
|
||||
Section: oldlibs
|
||||
Description: transitional dummy package for dump1090
|
||||
This is a transitional dummy package to handle upgrades from
|
||||
the old package name of "dump1090" to the new package name of
|
||||
"dump1090-fa". It can safely be removed.
|
||||
Vcs-Git: https://github.com/flightaware/dump1090.git
|
||||
|
||||
Package: dump1090-fa
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, adduser
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, adduser, lighttpd
|
||||
Description: FlightAware ADS-B Ground Station System for SDRs
|
||||
Networked Aviation Mode S / ADS-B decoder/translator with support
|
||||
for RTL-SDR, BladeRF, HackRF, and LimeSDR software defined radio USB
|
||||
|
|
|
|||
|
|
@ -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 ADSB --gain -10 --ppm 0"
|
||||
DECODER_OPTIONS="--max-range 800 --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
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
public_html/* usr/share/dump1090-fa/html
|
||||
public_html_merged/* usr/share/skyaware/html
|
||||
public_html/* usr/share/skyaware/html
|
||||
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/
|
||||
|
|
|
|||
|
|
@ -34,44 +34,21 @@ case "$1" in
|
|||
# plugdev required for bladeRF USB access
|
||||
adduser "$RUNAS" plugdev
|
||||
|
||||
# Make sure the "data" directory is owned by dump1090 so the dump1090-fa process has write access
|
||||
jsondir="/usr/share/dump1090-fa/html/data"
|
||||
if [ ! -d ${jsondir} ]; then
|
||||
echo "Creating directory ${jsondir}..." >&2
|
||||
mkdir ${jsondir}
|
||||
fi
|
||||
if [ -d ${jsondir} ]; then
|
||||
echo "Changing permissions on ${jsondir}..." >&2
|
||||
chown ${RUNAS}:nogroup ${jsondir}
|
||||
chmod 755 ${jsondir}
|
||||
fi
|
||||
|
||||
# Update apache
|
||||
changed=false
|
||||
for apachefile in /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/default-ssl.conf
|
||||
do
|
||||
if [ -f ${apachefile} ]; then
|
||||
echo "Modifying ${apachefile}..." >&2
|
||||
sed -i '/<\/VirtualHost>/i \
|
||||
####dump1090-start###\
|
||||
Alias "/data" "/dump1090-fa/data"\
|
||||
Alias "/dump1090-fa" "/usr/share/dump1090-fa/html"\
|
||||
Alias "^/dump1090-fa$" "/dump1090-fa"\
|
||||
SetEnvIf Request_URI "/dump1090-fa/data/.*\.json$" Header set "Access-Control-Allow-Origin" "*"\
|
||||
####dump1090-end###' ${apachefile}
|
||||
changed=true
|
||||
fi
|
||||
done
|
||||
|
||||
# Restart apache
|
||||
if $changed
|
||||
# set up lighttpd
|
||||
if dpkg --compare-versions "$2" lt "3.1.0"
|
||||
then
|
||||
echo "Restarting Apache..." >&2
|
||||
invoke-rc.d apache2 restart || echo "Warning: apache2 failed to restart." >&2
|
||||
echo "Enabling lighttpd integration.." >&2
|
||||
lighty-enable-mod dump1090-fa || true
|
||||
|
||||
# only enable the statcache config if there is nothing else around that already
|
||||
# configures it, because lighttpd fails if it's configured twice
|
||||
if ! grep -q -E '^\S*server.stat-cache-engine' /etc/lighttpd/conf-enabled/*.conf
|
||||
then
|
||||
echo "Enabling lighttpd integration (stat cache).." >&2
|
||||
lighty-enable-mod dump1090-fa-statcache || true
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
|
||||
# on upgrade, add an ENABLED line if it's not already present
|
||||
if dpkg --compare-versions "$2" lt-nl "3.7.0"
|
||||
then
|
||||
|
|
@ -86,14 +63,36 @@ case "$1" in
|
|||
fi
|
||||
fi
|
||||
|
||||
# enabling and starting the dump1090-fa service
|
||||
echo "Unmasking the dump1090-fa service..." >&2
|
||||
systemctl unmask dump1090-fa
|
||||
echo "Enabling the dump1090-fa service..." >&2
|
||||
systemctl enable dump1090-fa
|
||||
echo "Starting the dump1090-fa service..." >&2
|
||||
systemctl restart dump1090-fa
|
||||
# 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
|
||||
lighty-enable-mod skyaware || true
|
||||
|
||||
fi
|
||||
|
||||
# dump1090-fa lighttpd module deprecated in 7.2
|
||||
if dpkg --compare-versions "$2" lt "7.2"
|
||||
then
|
||||
if [ -e /etc/lighttpd/conf-enabled/89-dump1090-fa.conf ]
|
||||
then
|
||||
echo "Disabling deprecated lighttpd dump1090-fa module..." >&2
|
||||
lighty-disable-mod dump1090-fa || true
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Restarting lighttpd.." >&2
|
||||
invoke-rc.d lighttpd restart || true
|
||||
;;
|
||||
|
||||
abort-upgrade|abort-remove|abort-deconfigure)
|
||||
|
|
|
|||
|
|
@ -26,21 +26,24 @@ case "$1" in
|
|||
|
||||
remove)
|
||||
changed=false
|
||||
if [ -e /etc/lighttpd/conf-enabled/89-dump1090-fa.conf ]
|
||||
then
|
||||
echo "Disabling lighttpd integration.." >&2
|
||||
lighty-disable-mod dump1090-fa || true
|
||||
changed=true
|
||||
fi
|
||||
|
||||
for apachefile in /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/default-ssl.conf
|
||||
do
|
||||
if [ -f ${apachefile} ]; then
|
||||
echo "Modifying apache file ${apachefile}..." >&2
|
||||
sed -i '/^[ \t]*#*dump1090-start#*/,/^[ \t]*#*dump1090-end#*/{/^[ \t]*#*dump1090-start#*/!{/^[ \t]*#*dump1090-end#*/!d}}' ${apachefile}
|
||||
sed -i '/[ \t]*#*dump1090-start#*/,/^[ \t]*#*dump1090-end#*/d' ${apachefile}
|
||||
changed=true
|
||||
fi
|
||||
done
|
||||
if [ -e /etc/lighttpd/conf-enabled/88-dump1090-fa-statcache.conf ]
|
||||
then
|
||||
echo "Disabling lighttpd integration (stat cache).." >&2
|
||||
lighty-disable-mod dump1090-fa-statcache || true
|
||||
changed=true
|
||||
fi
|
||||
|
||||
if $changed
|
||||
then
|
||||
echo "Restarting Apache..." >&2
|
||||
invoke-rc.d apache2 restart || echo "Warning: apache2 failed to restart." >&2
|
||||
echo "Restarting lighttpd.." >&2
|
||||
invoke-rc.d lighttpd restart || echo "Warning: lighttpd failed to restart." >&2
|
||||
fi
|
||||
;;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ After=network.target
|
|||
User=dump1090
|
||||
RuntimeDirectory=dump1090-fa
|
||||
RuntimeDirectoryMode=0755
|
||||
ExecStart=/usr/share/dump1090-fa/start-dump1090-fa --write-json /usr/share/dump1090-fa/html/data --quiet
|
||||
ExecStart=/usr/share/dump1090-fa/start-dump1090-fa --write-json %t/dump1090-fa
|
||||
SyslogIdentifier=dump1090-fa
|
||||
Type=simple
|
||||
Restart=on-failure
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
# The stat cache must be disabled, as aircraft.json changes
|
||||
# frequently and lighttpd's stat cache often ends up with the
|
||||
# wrong content length.
|
||||
server.stat-cache-engine = "disable"
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
# Allows access to the static files that provide the dump1090 map view,
|
||||
# and also to the dynamically-generated json parts that contain aircraft
|
||||
# data and are periodically written by the dump1090 daemon.
|
||||
|
||||
# Enable alias module
|
||||
#
|
||||
## This module is normally already enabled in lighttpd, so you should not
|
||||
## need to uncommment this line.
|
||||
## There are some cases (e.g. when installing this on a Raspberry Pi
|
||||
## that runs PiHole) in which the module has been removed from the
|
||||
## default configuration, and the dump1090-fa web interface no longer
|
||||
## loads properly.
|
||||
## If this is what you are experiencing, or if you see messages in your
|
||||
## error log like:
|
||||
## (server.c.1493) WARNING: unknown config-key: alias.url (ignored)
|
||||
## then uncommenting this line and then restarting lighttpd could fix
|
||||
## the issue.
|
||||
## This is not enabled by default as standard lighttpd will not start if
|
||||
## modules are loaded multiple times.
|
||||
#
|
||||
# server.modules += ( "mod_alias" )
|
||||
|
||||
alias.url += (
|
||||
"/skyaware/data/" => "/run/dump1090-fa/",
|
||||
"/skyaware/data-978/" => "/run/skyaware978/",
|
||||
"/skyaware/" => "/usr/share/skyaware/html/"
|
||||
)
|
||||
|
||||
# redirect the slash-less URL
|
||||
url.redirect += (
|
||||
"^/skyaware$" => "/skyaware/"
|
||||
)
|
||||
|
||||
# Listen on port 8080 and serve the map there, too.
|
||||
$SERVER["socket"] == ":8080" {
|
||||
alias.url += (
|
||||
"/data/" => "/run/dump1090-fa/",
|
||||
"/data-978/" => "/run/skyaware978/",
|
||||
"/" => "/usr/share/skyaware/html/"
|
||||
)
|
||||
}
|
||||
|
||||
# Add CORS header
|
||||
server.modules += ( "mod_setenv" )
|
||||
$HTTP["url"] =~ "^/skyaware/data/.*\.json$" {
|
||||
setenv.set-response-header = ( "Access-Control-Allow-Origin" => "*" )
|
||||
}
|
||||
|
||||
# Uncomment this section to enable SSL traffic (HTTPS) - especially useful
|
||||
# for .dev domains
|
||||
## Listen on 8443 for SSL connections
|
||||
#server.modules += ( "mod_openssl" )
|
||||
#$HTTP["host"] == "piaware.example.com" {
|
||||
# $SERVER["socket"] == ":8443" {
|
||||
# ssl.engine = "enable"
|
||||
# ssl.pemfile = "/etc/ssl/certs/combined.pem"
|
||||
# ssl.ca-file = "/etc/ssl/certs/fullchain.cer"
|
||||
# ssl.honor-cipher-order = "enable"
|
||||
# ssl.cipher-list = "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"
|
||||
# ssl.use-sslv2 = "disable"
|
||||
# ssl.use-sslv3 = "disable"
|
||||
#
|
||||
# alias.url += (
|
||||
# "/data/" => "/run/dump1090-fa/",
|
||||
# "/" => "/usr/share/skyware/html/"
|
||||
# )
|
||||
# }
|
||||
#}
|
||||
#
|
||||
## Redirect HTTP to HTTPS
|
||||
#$HTTP["scheme"] == "http" {
|
||||
# $HTTP["host"] =~ ".*" {
|
||||
# url.redirect = (".*" => "https://%0$0")
|
||||
# }
|
||||
#}
|
||||
|
|
@ -53,5 +53,11 @@ override_dh_install:
|
|||
cp -a dump1090 debian/dump1090-fa/usr/bin/dump1090-fa
|
||||
cp -a view1090 debian/dump1090-fa/usr/bin/view1090-fa
|
||||
|
||||
override_dh_installinit:
|
||||
dh_installinit --no-stop-on-upgrade --no-restart-after-upgrade
|
||||
|
||||
override_dh_systemd_start:
|
||||
dh_systemd_start --no-stop-on-upgrade --no-restart-after-upgrade --name=dump1090-fa.service
|
||||
|
||||
%:
|
||||
dh $@ --with=systemd
|
||||
|
|
|
|||
|
|
@ -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,187 @@
|
|||
#!/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
|
||||
|
||||
# process all the options from the old config file and accumulate settings in env vars
|
||||
process_v5_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
|
||||
|
||||
# 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)
|
||||
|
||||
if [ "$CONFIG_STYLE" = "5" ]
|
||||
then
|
||||
echo "Generating a v6-style config from the v5-style config in $OLDCONFIG" >&2
|
||||
|
||||
# nb: all values either derived from env vars or the package defaults
|
||||
process_v5_options $RECEIVER_OPTIONS $DECODER_OPTIONS $NET_OPTIONS $JSON_OPTIONS
|
||||
FROMCONFIG=$PACKAGECONFIG
|
||||
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"@
|
||||
EOF
|
||||
|
||||
else
|
||||
# Existing config file doesn't seem to be a v5, just turn off adaptive gain settings
|
||||
# as this is an upgrade but otherwise leave it unchanged. (This happens when
|
||||
# there were no changes made by the user to the config file before upgrading; dpkg
|
||||
# will install the new v6 default config file automatically in that case)
|
||||
FROMCONFIG=$OLDCONFIG
|
||||
fi
|
||||
|
||||
# All upgrades get adaptive gain defaulting to off, to preserve the behaviour of
|
||||
# existing installs. New installs using the package defaults will default to on.
|
||||
echo "Disabling adaptive gain in $OLDCONFIG as this is an upgrade from pre-v6" >&2
|
||||
cat >>$SEDSCRIPT <<EOF
|
||||
s@^ADAPTIVE_DYNAMIC_RANGE=.*@ADAPTIVE_DYNAMIC_RANGE=no@
|
||||
s@^ADAPTIVE_BURST=.*@ADAPTIVE_BURST=no@
|
||||
EOF
|
||||
|
||||
# substitute into the config file template to generate our customized config
|
||||
if ! sed -f $SEDSCRIPT <$FROMCONFIG >$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
|
||||
96
demod_2400.c
96
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,17 @@ void demodulate2400(struct mag_buf *mag)
|
|||
unsigned char msg1[MODES_LONG_MSG_BYTES], msg2[MODES_LONG_MSG_BYTES], *msg;
|
||||
uint32_t j;
|
||||
|
||||
static unsigned last_message_end = 0;
|
||||
|
||||
// initialize bitsets on first call
|
||||
if (!valid_df_short_bitset)
|
||||
init_bitsets();
|
||||
|
||||
if (mag->flags & MAGBUF_DISCONTINUOUS) {
|
||||
// gap, start from the very beginning
|
||||
last_message_end = 0;
|
||||
}
|
||||
|
||||
unsigned char *bestmsg;
|
||||
int bestscore, bestphase;
|
||||
|
||||
|
|
@ -82,7 +127,11 @@ void demodulate2400(struct mag_buf *mag)
|
|||
|
||||
msg = msg1;
|
||||
|
||||
for (j = 0; j < mlen; j++) {
|
||||
// sanity check
|
||||
if (last_message_end > mlen)
|
||||
last_message_end = mlen;
|
||||
|
||||
for (j = last_message_end; j < mlen; j++) {
|
||||
uint16_t *preamble = &m[j];
|
||||
int high;
|
||||
uint32_t base_signal, base_noise;
|
||||
|
|
@ -173,7 +222,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 +230,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 +313,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.
|
||||
|
|
@ -336,13 +402,21 @@ void demodulate2400(struct mag_buf *mag)
|
|||
Modes.stats_current.strong_signal_count++; // signal power above -3dBFS
|
||||
}
|
||||
|
||||
// Feed "empty" sample to adaptive gain logic
|
||||
if (j > last_message_end)
|
||||
adaptive_update(&m[last_message_end], j - last_message_end, NULL);
|
||||
|
||||
// Feed message samples to adaptive gain logic, update end pointer
|
||||
last_message_end = j + (msglen + 8) * 12/5;
|
||||
adaptive_update(&m[j], last_message_end - j, &mm);
|
||||
|
||||
// Skip over the message:
|
||||
// (we actually skip to 8 bits before the end of the message,
|
||||
// because we can often decode two messages that *almost* collide,
|
||||
// where the preamble of the second message clobbered the last
|
||||
// few bits of the first message, but the message bits didn't
|
||||
// overlap)
|
||||
j += msglen*12/5;
|
||||
j = last_message_end - 8*12/5;
|
||||
|
||||
// Pass data to the next layer
|
||||
useModesMessage(&mm);
|
||||
|
|
@ -354,8 +428,20 @@ void demodulate2400(struct mag_buf *mag)
|
|||
Modes.stats_current.noise_power_sum += (mag->mean_power * mlen - sum_signal_power);
|
||||
Modes.stats_current.noise_power_count += mlen;
|
||||
}
|
||||
}
|
||||
|
||||
// feed trailing empty samples to adaptive gain logic
|
||||
if (last_message_end < mlen) {
|
||||
// trailing data from end of last message to start of overlap;
|
||||
// on the next pass, start from the start of the overlap
|
||||
adaptive_update(&m[last_message_end], mlen - last_message_end, NULL);
|
||||
last_message_end = 0;
|
||||
} else {
|
||||
// last decoded message runs into the overlap region;
|
||||
// on the next pass, start at the right place in the overlap;
|
||||
// no trailing data to pass this time
|
||||
last_message_end -= mlen;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MODEAC_DEBUG
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@ typedef union {
|
|||
typedef struct {
|
||||
int16_t I;
|
||||
int16_t Q;
|
||||
} __attribute__((__packed__)) sc16_t;
|
||||
} __attribute__((__packed__, __aligned__(2))) sc16_t;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
void STARCH_BENCHMARK(count_above_u16) (void)
|
||||
{
|
||||
uint16_t *in = NULL;
|
||||
const unsigned len = 96; /* Typical use is with short burst windows (40us) */
|
||||
const unsigned threshold = 46395; /* -3dBFS */
|
||||
|
||||
if (!(in = STARCH_BENCHMARK_ALLOC(len, uint16_t))) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
srand(1);
|
||||
for (unsigned i = 0; i < len; ++i) {
|
||||
in[i] = rand() % 65536;
|
||||
}
|
||||
|
||||
unsigned count;
|
||||
STARCH_BENCHMARK_RUN( count_above_u16, in, len, threshold, &count );
|
||||
|
||||
done:
|
||||
STARCH_BENCHMARK_FREE(in);
|
||||
}
|
||||
|
||||
bool STARCH_BENCHMARK_VERIFY(count_above_u16) (const uint16_t *in, unsigned len, uint16_t threshold, unsigned *out_count)
|
||||
{
|
||||
unsigned expected = 0;
|
||||
for (unsigned i = 0; i < len; ++i) {
|
||||
if (in[i] >= threshold)
|
||||
++expected;
|
||||
}
|
||||
|
||||
if (expected != *out_count) {
|
||||
fprintf(stderr, "verification failed: expected count %u, got count %u\n", expected, *out_count);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
@ -112,6 +122,230 @@ static bool starch_benchmark_flavor_in_list(const char *flavor, const starch_ben
|
|||
}
|
||||
|
||||
|
||||
/* prototypes for benchmark helpers provided by user code */
|
||||
void starch_count_above_u16_benchmark (void);
|
||||
bool starch_count_above_u16_benchmark_verify ( const uint16_t * arg0, unsigned arg1, uint16_t arg2, unsigned * arg3 );
|
||||
|
||||
/* prototype the benchmarking function so that we can build with -Wmissing-declarations */
|
||||
void starch_count_above_u16_benchmark(void);
|
||||
|
||||
static void starch_benchmark_one_count_above_u16( starch_count_above_u16_regentry * _entry, const uint16_t * arg0, unsigned arg1, uint16_t arg2, unsigned * arg3 )
|
||||
{
|
||||
fprintf(stderr, " %-40s ", _entry->name);
|
||||
|
||||
/* test for support */
|
||||
if (_entry->flavor_supported && !(_entry->flavor_supported())) {
|
||||
fprintf(stderr, "unsupported\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (starch_benchmark_flavor_whitelist && !starch_benchmark_flavor_in_list(_entry->flavor, starch_benchmark_flavor_whitelist)) {
|
||||
fprintf(stderr, "skipped (not whitelisted)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (starch_benchmark_flavor_blacklist && starch_benchmark_flavor_in_list(_entry->flavor, starch_benchmark_flavor_blacklist)) {
|
||||
fprintf(stderr, "skipped (blacklisted)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (starch_benchmark_list_only) {
|
||||
fprintf(stderr, "supported\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* initial warmup */
|
||||
for (unsigned _loop = 0; _loop < starch_benchmark_warmup_loops; ++_loop)
|
||||
_entry->callable ( arg0, arg1, arg2, arg3 );
|
||||
|
||||
/* verify correctness of the output */
|
||||
if (! starch_count_above_u16_benchmark_verify ( arg0, arg1, arg2, arg3 )) {
|
||||
fprintf(stderr, "skipped (verification failed)\n");
|
||||
starch_benchmark_validation_failed = true;
|
||||
return;
|
||||
}
|
||||
if (starch_benchmark_validate_only) {
|
||||
fprintf(stderr, "validation ok\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* pre-benchmark, find a loop count that takes at least 100ms */
|
||||
starch_benchmark_time _start, _end;
|
||||
uint64_t _elapsed = 0;
|
||||
uint64_t _loops = 127;
|
||||
while (_elapsed < 100000000) {
|
||||
_loops *= 2;
|
||||
starch_benchmark_get_time(&_start);
|
||||
for (uint64_t _loop = 0; _loop < _loops; ++_loop)
|
||||
_entry->callable ( arg0, arg1, arg2, arg3 );
|
||||
starch_benchmark_get_time(&_end);
|
||||
_elapsed = starch_benchmark_elapsed(&_start, &_end);
|
||||
}
|
||||
|
||||
/* real benchmark, run for approx 1 second */
|
||||
_loops = _loops * 1000000000 / _elapsed;
|
||||
|
||||
_elapsed = 0;
|
||||
uint64_t _elapsed_min = UINT64_MAX;
|
||||
uint64_t _elapsed_max = 0;
|
||||
for (unsigned _iter = 0; _iter < starch_benchmark_iterations; ++_iter) {
|
||||
starch_benchmark_get_time(&_start);
|
||||
for (uint64_t _loop = 0; _loop < _loops; ++_loop)
|
||||
_entry->callable ( arg0, arg1, arg2, arg3 );
|
||||
starch_benchmark_get_time(&_end);
|
||||
uint64_t _elapsed_one = starch_benchmark_elapsed(&_start, &_end);
|
||||
if (_elapsed_one < _elapsed_min)
|
||||
_elapsed_min = _elapsed_one;
|
||||
if (_elapsed_one > _elapsed_max)
|
||||
_elapsed_max = _elapsed_one;
|
||||
_elapsed += _elapsed_one;
|
||||
}
|
||||
|
||||
uint64_t _per_loop;
|
||||
if (starch_benchmark_iterations > 2)
|
||||
_per_loop = (_elapsed - _elapsed_min - _elapsed_max) / _loops / (starch_benchmark_iterations - 2);
|
||||
else
|
||||
_per_loop = _elapsed / _loops / starch_benchmark_iterations;
|
||||
|
||||
fprintf(stderr, "%" PRIu64 " ns/call\n", _per_loop);
|
||||
|
||||
if (starch_benchmark_result_count >= starch_benchmark_result_size) {
|
||||
if (!starch_benchmark_result_size)
|
||||
starch_benchmark_result_size = 64;
|
||||
else
|
||||
starch_benchmark_result_size *= 2;
|
||||
starch_benchmark_results = realloc(starch_benchmark_results, starch_benchmark_result_size * sizeof(*starch_benchmark_results));
|
||||
if (!starch_benchmark_results) {
|
||||
fprintf(stderr, "realloc: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
starch_benchmark_results[starch_benchmark_result_count].name = "count_above_u16";
|
||||
starch_benchmark_results[starch_benchmark_result_count].impl = _entry->name;
|
||||
starch_benchmark_results[starch_benchmark_result_count].ns = _per_loop;
|
||||
++starch_benchmark_result_count;
|
||||
}
|
||||
|
||||
static void starch_benchmark_run_count_above_u16( const uint16_t * arg0, unsigned arg1, uint16_t arg2, unsigned * arg3 )
|
||||
{
|
||||
for (starch_count_above_u16_regentry *_entry = starch_count_above_u16_registry; _entry->name; ++_entry) {
|
||||
starch_benchmark_one_count_above_u16( _entry, arg0, arg1, arg2, arg3 );
|
||||
}
|
||||
}
|
||||
|
||||
/* prototypes for benchmark helpers provided by user code */
|
||||
void starch_count_above_u16_aligned_benchmark (void);
|
||||
bool starch_count_above_u16_aligned_benchmark_verify ( const uint16_t * arg0, unsigned arg1, uint16_t arg2, unsigned * arg3 );
|
||||
|
||||
/* prototype the benchmarking function so that we can build with -Wmissing-declarations */
|
||||
void starch_count_above_u16_aligned_benchmark(void);
|
||||
|
||||
static void starch_benchmark_one_count_above_u16_aligned( starch_count_above_u16_aligned_regentry * _entry, const uint16_t * arg0, unsigned arg1, uint16_t arg2, unsigned * arg3 )
|
||||
{
|
||||
fprintf(stderr, " %-40s ", _entry->name);
|
||||
|
||||
/* test for support */
|
||||
if (_entry->flavor_supported && !(_entry->flavor_supported())) {
|
||||
fprintf(stderr, "unsupported\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (starch_benchmark_flavor_whitelist && !starch_benchmark_flavor_in_list(_entry->flavor, starch_benchmark_flavor_whitelist)) {
|
||||
fprintf(stderr, "skipped (not whitelisted)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (starch_benchmark_flavor_blacklist && starch_benchmark_flavor_in_list(_entry->flavor, starch_benchmark_flavor_blacklist)) {
|
||||
fprintf(stderr, "skipped (blacklisted)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (starch_benchmark_list_only) {
|
||||
fprintf(stderr, "supported\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* initial warmup */
|
||||
for (unsigned _loop = 0; _loop < starch_benchmark_warmup_loops; ++_loop)
|
||||
_entry->callable ( arg0, arg1, arg2, arg3 );
|
||||
|
||||
/* verify correctness of the output */
|
||||
if (! starch_count_above_u16_aligned_benchmark_verify ( arg0, arg1, arg2, arg3 )) {
|
||||
fprintf(stderr, "skipped (verification failed)\n");
|
||||
starch_benchmark_validation_failed = true;
|
||||
return;
|
||||
}
|
||||
if (starch_benchmark_validate_only) {
|
||||
fprintf(stderr, "validation ok\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* pre-benchmark, find a loop count that takes at least 100ms */
|
||||
starch_benchmark_time _start, _end;
|
||||
uint64_t _elapsed = 0;
|
||||
uint64_t _loops = 127;
|
||||
while (_elapsed < 100000000) {
|
||||
_loops *= 2;
|
||||
starch_benchmark_get_time(&_start);
|
||||
for (uint64_t _loop = 0; _loop < _loops; ++_loop)
|
||||
_entry->callable ( arg0, arg1, arg2, arg3 );
|
||||
starch_benchmark_get_time(&_end);
|
||||
_elapsed = starch_benchmark_elapsed(&_start, &_end);
|
||||
}
|
||||
|
||||
/* real benchmark, run for approx 1 second */
|
||||
_loops = _loops * 1000000000 / _elapsed;
|
||||
|
||||
_elapsed = 0;
|
||||
uint64_t _elapsed_min = UINT64_MAX;
|
||||
uint64_t _elapsed_max = 0;
|
||||
for (unsigned _iter = 0; _iter < starch_benchmark_iterations; ++_iter) {
|
||||
starch_benchmark_get_time(&_start);
|
||||
for (uint64_t _loop = 0; _loop < _loops; ++_loop)
|
||||
_entry->callable ( arg0, arg1, arg2, arg3 );
|
||||
starch_benchmark_get_time(&_end);
|
||||
uint64_t _elapsed_one = starch_benchmark_elapsed(&_start, &_end);
|
||||
if (_elapsed_one < _elapsed_min)
|
||||
_elapsed_min = _elapsed_one;
|
||||
if (_elapsed_one > _elapsed_max)
|
||||
_elapsed_max = _elapsed_one;
|
||||
_elapsed += _elapsed_one;
|
||||
}
|
||||
|
||||
uint64_t _per_loop;
|
||||
if (starch_benchmark_iterations > 2)
|
||||
_per_loop = (_elapsed - _elapsed_min - _elapsed_max) / _loops / (starch_benchmark_iterations - 2);
|
||||
else
|
||||
_per_loop = _elapsed / _loops / starch_benchmark_iterations;
|
||||
|
||||
fprintf(stderr, "%" PRIu64 " ns/call\n", _per_loop);
|
||||
|
||||
if (starch_benchmark_result_count >= starch_benchmark_result_size) {
|
||||
if (!starch_benchmark_result_size)
|
||||
starch_benchmark_result_size = 64;
|
||||
else
|
||||
starch_benchmark_result_size *= 2;
|
||||
starch_benchmark_results = realloc(starch_benchmark_results, starch_benchmark_result_size * sizeof(*starch_benchmark_results));
|
||||
if (!starch_benchmark_results) {
|
||||
fprintf(stderr, "realloc: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
starch_benchmark_results[starch_benchmark_result_count].name = "count_above_u16_aligned";
|
||||
starch_benchmark_results[starch_benchmark_result_count].impl = _entry->name;
|
||||
starch_benchmark_results[starch_benchmark_result_count].ns = _per_loop;
|
||||
++starch_benchmark_result_count;
|
||||
}
|
||||
|
||||
static void starch_benchmark_run_count_above_u16_aligned( const uint16_t * arg0, unsigned arg1, uint16_t arg2, unsigned * arg3 )
|
||||
{
|
||||
for (starch_count_above_u16_aligned_regentry *_entry = starch_count_above_u16_aligned_registry; _entry->name; ++_entry) {
|
||||
starch_benchmark_one_count_above_u16_aligned( _entry, arg0, arg1, arg2, arg3 );
|
||||
}
|
||||
}
|
||||
|
||||
/* prototypes for benchmark helpers provided by user code */
|
||||
void starch_magnitude_power_uc8_benchmark (void);
|
||||
bool starch_magnitude_power_uc8_benchmark_verify ( const uc8_t * arg0, uint16_t * arg1, unsigned arg2, double * arg3, double * arg4 );
|
||||
|
|
@ -1246,6 +1480,7 @@ static void starch_benchmark_run_mean_power_u16_aligned( const uint16_t * arg0,
|
|||
#define STARCH_BENCHMARK_ALLOC(_count, _type) ((_type *) starch_benchmark_aligned_alloc(1, alignof(_type), (_count) * sizeof(_type)))
|
||||
#define STARCH_BENCHMARK_FREE(_ptr) starch_benchmark_aligned_free(_ptr)
|
||||
|
||||
#include "../benchmark/count_above_u16_benchmark.c"
|
||||
#include "../benchmark/magnitude_power_uc8_benchmark.c"
|
||||
#include "../benchmark/magnitude_sc16_benchmark.c"
|
||||
#include "../benchmark/magnitude_sc16q11_benchmark.c"
|
||||
|
|
@ -1274,12 +1509,23 @@ static void starch_benchmark_run_mean_power_u16_aligned( const uint16_t * arg0,
|
|||
#define STARCH_BENCHMARK_ALLOC(_count, _type) ((_type *) starch_benchmark_aligned_alloc(STARCH_MIX_ALIGNMENT, alignof(_type), (_count) * sizeof(_type)))
|
||||
#define STARCH_BENCHMARK_FREE(_ptr) starch_benchmark_aligned_free(_ptr)
|
||||
|
||||
#include "../benchmark/count_above_u16_benchmark.c"
|
||||
#include "../benchmark/magnitude_power_uc8_benchmark.c"
|
||||
#include "../benchmark/magnitude_sc16_benchmark.c"
|
||||
#include "../benchmark/magnitude_sc16q11_benchmark.c"
|
||||
#include "../benchmark/magnitude_uc8_benchmark.c"
|
||||
#include "../benchmark/mean_power_u16_benchmark.c"
|
||||
|
||||
static void starch_benchmark_all_count_above_u16(void)
|
||||
{
|
||||
fprintf(stderr, "==== count_above_u16 ===\n");
|
||||
starch_count_above_u16_benchmark ();
|
||||
}
|
||||
static void starch_benchmark_all_count_above_u16_aligned(void)
|
||||
{
|
||||
fprintf(stderr, "==== count_above_u16_aligned ===\n");
|
||||
starch_count_above_u16_aligned_benchmark ();
|
||||
}
|
||||
static void starch_benchmark_all_magnitude_power_uc8(void)
|
||||
{
|
||||
fprintf(stderr, "==== magnitude_power_uc8 ===\n");
|
||||
|
|
@ -1383,6 +1629,8 @@ static void starch_benchmark_usage(const char *argv0)
|
|||
#endif
|
||||
"\n"
|
||||
"Supported functions: "
|
||||
"count_above_u16 "
|
||||
"count_above_u16_aligned "
|
||||
"magnitude_power_uc8 "
|
||||
"magnitude_power_uc8_aligned "
|
||||
"magnitude_sc16 "
|
||||
|
|
@ -1478,6 +1726,16 @@ int main(int argc, char **argv)
|
|||
}
|
||||
|
||||
for (int i = optind; i < argc; ++i) {
|
||||
if (!strcmp(argv[i], "count_above_u16")) {
|
||||
specific = 1;
|
||||
starch_benchmark_all_count_above_u16();
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "count_above_u16_aligned")) {
|
||||
specific = 1;
|
||||
starch_benchmark_all_count_above_u16_aligned();
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "magnitude_power_uc8")) {
|
||||
specific = 1;
|
||||
starch_benchmark_all_magnitude_power_uc8();
|
||||
|
|
@ -1534,6 +1792,8 @@ int main(int argc, char **argv)
|
|||
}
|
||||
|
||||
if (!specific) {
|
||||
starch_benchmark_all_count_above_u16();
|
||||
starch_benchmark_all_count_above_u16_aligned();
|
||||
starch_benchmark_all_magnitude_power_uc8();
|
||||
starch_benchmark_all_magnitude_power_uc8_aligned();
|
||||
starch_benchmark_all_magnitude_sc16();
|
||||
|
|
|
|||
|
|
@ -19,6 +19,165 @@ static int starch_regentry_rank_compare (const void *l, const void *r)
|
|||
return left->rank - right->rank;
|
||||
}
|
||||
|
||||
/* dispatcher / registry for count_above_u16 */
|
||||
|
||||
starch_count_above_u16_regentry * starch_count_above_u16_select() {
|
||||
for (starch_count_above_u16_regentry *entry = starch_count_above_u16_registry;
|
||||
entry->name;
|
||||
++entry)
|
||||
{
|
||||
if (entry->flavor_supported && !(entry->flavor_supported()))
|
||||
continue;
|
||||
return entry;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void starch_count_above_u16_dispatch ( const uint16_t * arg0, unsigned arg1, uint16_t arg2, unsigned * arg3 ) {
|
||||
starch_count_above_u16_regentry *entry = starch_count_above_u16_select();
|
||||
if (!entry)
|
||||
abort();
|
||||
|
||||
starch_count_above_u16 = entry->callable;
|
||||
starch_count_above_u16 ( arg0, arg1, arg2, arg3 );
|
||||
}
|
||||
|
||||
starch_count_above_u16_ptr starch_count_above_u16 = starch_count_above_u16_dispatch;
|
||||
|
||||
void starch_count_above_u16_set_wisdom (const char * const * received_wisdom)
|
||||
{
|
||||
/* re-rank the registry based on received wisdom */
|
||||
starch_count_above_u16_regentry *entry;
|
||||
for (entry = starch_count_above_u16_registry; entry->name; ++entry) {
|
||||
const char * const *search;
|
||||
for (search = received_wisdom; *search; ++search) {
|
||||
if (!strcmp(*search, entry->name)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*search) {
|
||||
/* matches an entry in the wisdom list, order by position in the list */
|
||||
entry->rank = search - received_wisdom;
|
||||
} else {
|
||||
/* no match, rank after all possible matches, retaining existing order */
|
||||
entry->rank = (search - received_wisdom) + (entry - starch_count_above_u16_registry);
|
||||
}
|
||||
}
|
||||
|
||||
/* re-sort based on the new ranking */
|
||||
qsort(starch_count_above_u16_registry, entry - starch_count_above_u16_registry, sizeof(starch_count_above_u16_regentry), starch_regentry_rank_compare);
|
||||
|
||||
/* reset the implementation pointer so the next call will re-select */
|
||||
starch_count_above_u16 = starch_count_above_u16_dispatch;
|
||||
}
|
||||
|
||||
starch_count_above_u16_regentry starch_count_above_u16_registry[] = {
|
||||
|
||||
#ifdef STARCH_MIX_AARCH64
|
||||
{ 0, "generic_armv8_neon_simd", "armv8_neon_simd", starch_count_above_u16_generic_armv8_neon_simd, cpu_supports_armv8_simd },
|
||||
{ 1, "neon_armv8_neon_simd", "armv8_neon_simd", starch_count_above_u16_neon_armv8_neon_simd, cpu_supports_armv8_simd },
|
||||
{ 2, "generic_generic", "generic", starch_count_above_u16_generic_generic, NULL },
|
||||
#endif /* STARCH_MIX_AARCH64 */
|
||||
|
||||
#ifdef STARCH_MIX_ARM
|
||||
{ 0, "neon_armv7a_neon_vfpv4", "armv7a_neon_vfpv4", starch_count_above_u16_neon_armv7a_neon_vfpv4, cpu_supports_armv7_neon_vfpv4 },
|
||||
{ 1, "generic_generic", "generic", starch_count_above_u16_generic_generic, NULL },
|
||||
{ 2, "generic_armv7a_neon_vfpv4", "armv7a_neon_vfpv4", starch_count_above_u16_generic_armv7a_neon_vfpv4, cpu_supports_armv7_neon_vfpv4 },
|
||||
#endif /* STARCH_MIX_ARM */
|
||||
|
||||
#ifdef STARCH_MIX_GENERIC
|
||||
{ 0, "generic_generic", "generic", starch_count_above_u16_generic_generic, NULL },
|
||||
#endif /* STARCH_MIX_GENERIC */
|
||||
|
||||
#ifdef STARCH_MIX_X86
|
||||
{ 0, "generic_x86_avx2", "x86_avx2", starch_count_above_u16_generic_x86_avx2, cpu_supports_avx2 },
|
||||
{ 1, "generic_generic", "generic", starch_count_above_u16_generic_generic, NULL },
|
||||
#endif /* STARCH_MIX_X86 */
|
||||
{ 0, NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
/* dispatcher / registry for count_above_u16_aligned */
|
||||
|
||||
starch_count_above_u16_aligned_regentry * starch_count_above_u16_aligned_select() {
|
||||
for (starch_count_above_u16_aligned_regentry *entry = starch_count_above_u16_aligned_registry;
|
||||
entry->name;
|
||||
++entry)
|
||||
{
|
||||
if (entry->flavor_supported && !(entry->flavor_supported()))
|
||||
continue;
|
||||
return entry;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void starch_count_above_u16_aligned_dispatch ( const uint16_t * arg0, unsigned arg1, uint16_t arg2, unsigned * arg3 ) {
|
||||
starch_count_above_u16_aligned_regentry *entry = starch_count_above_u16_aligned_select();
|
||||
if (!entry)
|
||||
abort();
|
||||
|
||||
starch_count_above_u16_aligned = entry->callable;
|
||||
starch_count_above_u16_aligned ( arg0, arg1, arg2, arg3 );
|
||||
}
|
||||
|
||||
starch_count_above_u16_aligned_ptr starch_count_above_u16_aligned = starch_count_above_u16_aligned_dispatch;
|
||||
|
||||
void starch_count_above_u16_aligned_set_wisdom (const char * const * received_wisdom)
|
||||
{
|
||||
/* re-rank the registry based on received wisdom */
|
||||
starch_count_above_u16_aligned_regentry *entry;
|
||||
for (entry = starch_count_above_u16_aligned_registry; entry->name; ++entry) {
|
||||
const char * const *search;
|
||||
for (search = received_wisdom; *search; ++search) {
|
||||
if (!strcmp(*search, entry->name)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*search) {
|
||||
/* matches an entry in the wisdom list, order by position in the list */
|
||||
entry->rank = search - received_wisdom;
|
||||
} else {
|
||||
/* no match, rank after all possible matches, retaining existing order */
|
||||
entry->rank = (search - received_wisdom) + (entry - starch_count_above_u16_aligned_registry);
|
||||
}
|
||||
}
|
||||
|
||||
/* re-sort based on the new ranking */
|
||||
qsort(starch_count_above_u16_aligned_registry, entry - starch_count_above_u16_aligned_registry, sizeof(starch_count_above_u16_aligned_regentry), starch_regentry_rank_compare);
|
||||
|
||||
/* reset the implementation pointer so the next call will re-select */
|
||||
starch_count_above_u16_aligned = starch_count_above_u16_aligned_dispatch;
|
||||
}
|
||||
|
||||
starch_count_above_u16_aligned_regentry starch_count_above_u16_aligned_registry[] = {
|
||||
|
||||
#ifdef STARCH_MIX_AARCH64
|
||||
{ 0, "generic_armv8_neon_simd_aligned", "armv8_neon_simd", starch_count_above_u16_aligned_generic_armv8_neon_simd, cpu_supports_armv8_simd },
|
||||
{ 1, "neon_armv8_neon_simd_aligned", "armv8_neon_simd", starch_count_above_u16_aligned_neon_armv8_neon_simd, cpu_supports_armv8_simd },
|
||||
{ 2, "generic_armv8_neon_simd", "armv8_neon_simd", starch_count_above_u16_generic_armv8_neon_simd, cpu_supports_armv8_simd },
|
||||
{ 3, "neon_armv8_neon_simd", "armv8_neon_simd", starch_count_above_u16_neon_armv8_neon_simd, cpu_supports_armv8_simd },
|
||||
{ 4, "generic_generic", "generic", starch_count_above_u16_generic_generic, NULL },
|
||||
#endif /* STARCH_MIX_AARCH64 */
|
||||
|
||||
#ifdef STARCH_MIX_ARM
|
||||
{ 0, "neon_armv7a_neon_vfpv4", "armv7a_neon_vfpv4", starch_count_above_u16_neon_armv7a_neon_vfpv4, cpu_supports_armv7_neon_vfpv4 },
|
||||
{ 1, "generic_generic", "generic", starch_count_above_u16_generic_generic, NULL },
|
||||
{ 2, "generic_armv7a_neon_vfpv4_aligned", "armv7a_neon_vfpv4", starch_count_above_u16_aligned_generic_armv7a_neon_vfpv4, cpu_supports_armv7_neon_vfpv4 },
|
||||
{ 3, "neon_armv7a_neon_vfpv4_aligned", "armv7a_neon_vfpv4", starch_count_above_u16_aligned_neon_armv7a_neon_vfpv4, cpu_supports_armv7_neon_vfpv4 },
|
||||
{ 4, "generic_armv7a_neon_vfpv4", "armv7a_neon_vfpv4", starch_count_above_u16_generic_armv7a_neon_vfpv4, cpu_supports_armv7_neon_vfpv4 },
|
||||
#endif /* STARCH_MIX_ARM */
|
||||
|
||||
#ifdef STARCH_MIX_GENERIC
|
||||
{ 0, "generic_generic", "generic", starch_count_above_u16_generic_generic, NULL },
|
||||
#endif /* STARCH_MIX_GENERIC */
|
||||
|
||||
#ifdef STARCH_MIX_X86
|
||||
{ 0, "generic_x86_avx2_aligned", "x86_avx2", starch_count_above_u16_aligned_generic_x86_avx2, cpu_supports_avx2 },
|
||||
{ 1, "generic_generic", "generic", starch_count_above_u16_generic_generic, NULL },
|
||||
{ 2, "generic_x86_avx2", "x86_avx2", starch_count_above_u16_generic_x86_avx2, cpu_supports_avx2 },
|
||||
#endif /* STARCH_MIX_X86 */
|
||||
{ 0, NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
/* dispatcher / registry for magnitude_power_uc8 */
|
||||
|
||||
starch_magnitude_power_uc8_regentry * starch_magnitude_power_uc8_select() {
|
||||
|
|
@ -992,6 +1151,14 @@ int starch_read_wisdom (const char * path)
|
|||
return -1;
|
||||
|
||||
/* reset all ranks to identify entries not listed in the wisdom file; we'll assign ranks at the end to produce a stable sort */
|
||||
int rank_count_above_u16 = 0;
|
||||
for (starch_count_above_u16_regentry *entry = starch_count_above_u16_registry; entry->name; ++entry) {
|
||||
entry->rank = 0;
|
||||
}
|
||||
int rank_count_above_u16_aligned = 0;
|
||||
for (starch_count_above_u16_aligned_regentry *entry = starch_count_above_u16_aligned_registry; entry->name; ++entry) {
|
||||
entry->rank = 0;
|
||||
}
|
||||
int rank_magnitude_power_uc8 = 0;
|
||||
for (starch_magnitude_power_uc8_regentry *entry = starch_magnitude_power_uc8_registry; entry->name; ++entry) {
|
||||
entry->rank = 0;
|
||||
|
|
@ -1065,6 +1232,24 @@ int starch_read_wisdom (const char * path)
|
|||
*end = 0;
|
||||
|
||||
/* try to find a matching registry entry */
|
||||
if (!strcmp(name, "count_above_u16")) {
|
||||
for (starch_count_above_u16_regentry *entry = starch_count_above_u16_registry; entry->name; ++entry) {
|
||||
if (!strcmp(impl, entry->name)) {
|
||||
entry->rank = ++rank_count_above_u16;
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(name, "count_above_u16_aligned")) {
|
||||
for (starch_count_above_u16_aligned_regentry *entry = starch_count_above_u16_aligned_registry; entry->name; ++entry) {
|
||||
if (!strcmp(impl, entry->name)) {
|
||||
entry->rank = ++rank_count_above_u16_aligned;
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(name, "magnitude_power_uc8")) {
|
||||
for (starch_magnitude_power_uc8_regentry *entry = starch_magnitude_power_uc8_registry; entry->name; ++entry) {
|
||||
if (!strcmp(impl, entry->name)) {
|
||||
|
|
@ -1165,6 +1350,28 @@ int starch_read_wisdom (const char * path)
|
|||
fclose(fp);
|
||||
|
||||
/* assign ranks to unmatched items to (stable) sort them last; re-sort everything */
|
||||
{
|
||||
starch_count_above_u16_regentry *entry;
|
||||
for (entry = starch_count_above_u16_registry; entry->name; ++entry) {
|
||||
if (!entry->rank)
|
||||
entry->rank = ++rank_count_above_u16;
|
||||
}
|
||||
qsort(starch_count_above_u16_registry, entry - starch_count_above_u16_registry, sizeof(starch_count_above_u16_regentry), starch_regentry_rank_compare);
|
||||
|
||||
/* reset the implementation pointer so the next call will re-select */
|
||||
starch_count_above_u16 = starch_count_above_u16_dispatch;
|
||||
}
|
||||
{
|
||||
starch_count_above_u16_aligned_regentry *entry;
|
||||
for (entry = starch_count_above_u16_aligned_registry; entry->name; ++entry) {
|
||||
if (!entry->rank)
|
||||
entry->rank = ++rank_count_above_u16_aligned;
|
||||
}
|
||||
qsort(starch_count_above_u16_aligned_registry, entry - starch_count_above_u16_aligned_registry, sizeof(starch_count_above_u16_aligned_regentry), starch_regentry_rank_compare);
|
||||
|
||||
/* reset the implementation pointer so the next call will re-select */
|
||||
starch_count_above_u16_aligned = starch_count_above_u16_aligned_dispatch;
|
||||
}
|
||||
{
|
||||
starch_magnitude_power_uc8_regentry *entry;
|
||||
for (entry = starch_magnitude_power_uc8_registry; entry->name; ++entry) {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#define STARCH_IMPL(_function,_impl) starch_ ## _function ## _ ## _impl ## _ ## armv7a_neon_vfpv4
|
||||
#define STARCH_IMPL_REQUIRES(_function,_impl,_feature) STARCH_IMPL(_function,_impl)
|
||||
|
||||
#include "../impl/count_above_u16.c"
|
||||
#include "../impl/magnitude_power_uc8.c"
|
||||
#include "../impl/magnitude_sc16.c"
|
||||
#include "../impl/magnitude_sc16q11.c"
|
||||
|
|
@ -33,6 +34,7 @@
|
|||
#define STARCH_IMPL(_function,_impl) starch_ ## _function ## _aligned_ ## _impl ## _ ## armv7a_neon_vfpv4
|
||||
#define STARCH_IMPL_REQUIRES(_function,_impl,_feature) STARCH_IMPL(_function,_impl)
|
||||
|
||||
#include "../impl/count_above_u16.c"
|
||||
#include "../impl/magnitude_power_uc8.c"
|
||||
#include "../impl/magnitude_sc16.c"
|
||||
#include "../impl/magnitude_sc16q11.c"
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#define STARCH_IMPL(_function,_impl) starch_ ## _function ## _ ## _impl ## _ ## armv8_neon_simd
|
||||
#define STARCH_IMPL_REQUIRES(_function,_impl,_feature) STARCH_IMPL(_function,_impl)
|
||||
|
||||
#include "../impl/count_above_u16.c"
|
||||
#include "../impl/magnitude_power_uc8.c"
|
||||
#include "../impl/magnitude_sc16.c"
|
||||
#include "../impl/magnitude_sc16q11.c"
|
||||
|
|
@ -33,6 +34,7 @@
|
|||
#define STARCH_IMPL(_function,_impl) starch_ ## _function ## _aligned_ ## _impl ## _ ## armv8_neon_simd
|
||||
#define STARCH_IMPL_REQUIRES(_function,_impl,_feature) STARCH_IMPL(_function,_impl)
|
||||
|
||||
#include "../impl/count_above_u16.c"
|
||||
#include "../impl/magnitude_power_uc8.c"
|
||||
#include "../impl/magnitude_sc16.c"
|
||||
#include "../impl/magnitude_sc16q11.c"
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#define STARCH_IMPL(_function,_impl) starch_ ## _function ## _ ## _impl ## _ ## generic
|
||||
#define STARCH_IMPL_REQUIRES(_function,_impl,_feature) STARCH_IMPL(_function,_impl)
|
||||
|
||||
#include "../impl/count_above_u16.c"
|
||||
#include "../impl/magnitude_power_uc8.c"
|
||||
#include "../impl/magnitude_sc16.c"
|
||||
#include "../impl/magnitude_sc16q11.c"
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#define STARCH_IMPL(_function,_impl) starch_ ## _function ## _ ## _impl ## _ ## x86_avx2
|
||||
#define STARCH_IMPL_REQUIRES(_function,_impl,_feature) STARCH_IMPL(_function,_impl)
|
||||
|
||||
#include "../impl/count_above_u16.c"
|
||||
#include "../impl/magnitude_power_uc8.c"
|
||||
#include "../impl/magnitude_sc16.c"
|
||||
#include "../impl/magnitude_sc16q11.c"
|
||||
|
|
@ -32,6 +33,7 @@
|
|||
#define STARCH_IMPL(_function,_impl) starch_ ## _function ## _aligned_ ## _impl ## _ ## x86_avx2
|
||||
#define STARCH_IMPL_REQUIRES(_function,_impl,_feature) STARCH_IMPL(_function,_impl)
|
||||
|
||||
#include "../impl/count_above_u16.c"
|
||||
#include "../impl/magnitude_power_uc8.c"
|
||||
#include "../impl/magnitude_sc16.c"
|
||||
#include "../impl/magnitude_sc16q11.c"
|
||||
|
|
|
|||
|
|
@ -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/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
|
||||
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
|
||||
@$(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/magnitude_sc16.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/flavor.generic.c -o dsp/generated/flavor.generic.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
|
||||
@$(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/magnitude_sc16.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/dispatcher.c -o dsp/generated/dispatcher.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
|
||||
@$(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/magnitude_sc16q11_benchmark.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/benchmark.c -o dsp/generated/benchmark.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
|
||||
@$(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/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
|
||||
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
|
||||
@$(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/magnitude_sc16.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/flavor.generic.c -o dsp/generated/flavor.generic.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
|
||||
@$(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/magnitude_sc16.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/dispatcher.c -o dsp/generated/dispatcher.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
|
||||
@$(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/magnitude_sc16q11_benchmark.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/benchmark.c -o dsp/generated/benchmark.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
|
||||
@$(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/magnitude_sc16.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/flavor.generic.c -o dsp/generated/flavor.generic.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
|
||||
@$(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/magnitude_sc16.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/dispatcher.c -o dsp/generated/dispatcher.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
|
||||
@$(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/magnitude_sc16q11_benchmark.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/benchmark.c -o dsp/generated/benchmark.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
|
||||
@$(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/magnitude_sc16.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) -mavx2 -ffast-math dsp/generated/flavor.x86_avx2.c -o dsp/generated/flavor.x86_avx2.o
|
||||
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
|
||||
@$(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/magnitude_sc16.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/flavor.generic.c -o dsp/generated/flavor.generic.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
|
||||
@$(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/magnitude_sc16.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/dispatcher.c -o dsp/generated/dispatcher.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
|
||||
@$(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/magnitude_sc16q11_benchmark.c
|
||||
$(STARCH_COMPILE) $(STARCH_CFLAGS) dsp/generated/benchmark.c -o dsp/generated/benchmark.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
|
||||
@$(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
|
||||
|
|
|
|||
|
|
@ -195,6 +195,36 @@ extern starch_mean_power_u16_aligned_regentry starch_mean_power_u16_aligned_regi
|
|||
starch_mean_power_u16_aligned_regentry * starch_mean_power_u16_aligned_select();
|
||||
void starch_mean_power_u16_aligned_set_wisdom( const char * const * received_wisdom );
|
||||
|
||||
typedef void (* starch_count_above_u16_ptr) ( const uint16_t * arg0, unsigned arg1, uint16_t arg2, unsigned * arg3 );
|
||||
extern starch_count_above_u16_ptr starch_count_above_u16;
|
||||
|
||||
typedef struct {
|
||||
int rank;
|
||||
const char *name;
|
||||
const char *flavor;
|
||||
starch_count_above_u16_ptr callable;
|
||||
int (*flavor_supported)();
|
||||
} starch_count_above_u16_regentry;
|
||||
|
||||
extern starch_count_above_u16_regentry starch_count_above_u16_registry[];
|
||||
starch_count_above_u16_regentry * starch_count_above_u16_select();
|
||||
void starch_count_above_u16_set_wisdom( const char * const * received_wisdom );
|
||||
|
||||
typedef void (* starch_count_above_u16_aligned_ptr) ( const uint16_t * arg0, unsigned arg1, uint16_t arg2, unsigned * arg3 );
|
||||
extern starch_count_above_u16_aligned_ptr starch_count_above_u16_aligned;
|
||||
|
||||
typedef struct {
|
||||
int rank;
|
||||
const char *name;
|
||||
const char *flavor;
|
||||
starch_count_above_u16_aligned_ptr callable;
|
||||
int (*flavor_supported)();
|
||||
} starch_count_above_u16_aligned_regentry;
|
||||
|
||||
extern starch_count_above_u16_aligned_regentry starch_count_above_u16_aligned_registry[];
|
||||
starch_count_above_u16_aligned_regentry * starch_count_above_u16_aligned_select();
|
||||
void starch_count_above_u16_aligned_set_wisdom( const char * const * received_wisdom );
|
||||
|
||||
/* flavors and prototypes */
|
||||
|
||||
#ifdef STARCH_FLAVOR_ARMV7A_NEON_VFPV4
|
||||
|
|
@ -233,6 +263,10 @@ void starch_magnitude_sc16q11_12bit_table_armv7a_neon_vfpv4 ( const sc16_t * arg
|
|||
void starch_magnitude_sc16q11_aligned_12bit_table_armv7a_neon_vfpv4 ( const sc16_t * arg0, uint16_t * arg1, unsigned arg2 );
|
||||
void starch_magnitude_sc16q11_neon_vrsqrte_armv7a_neon_vfpv4 ( const sc16_t * arg0, uint16_t * arg1, unsigned arg2 );
|
||||
void starch_magnitude_sc16q11_aligned_neon_vrsqrte_armv7a_neon_vfpv4 ( const sc16_t * arg0, uint16_t * arg1, unsigned arg2 );
|
||||
void starch_count_above_u16_generic_armv7a_neon_vfpv4 ( const uint16_t * arg0, unsigned arg1, uint16_t arg2, unsigned * arg3 );
|
||||
void starch_count_above_u16_aligned_generic_armv7a_neon_vfpv4 ( const uint16_t * arg0, unsigned arg1, uint16_t arg2, unsigned * arg3 );
|
||||
void starch_count_above_u16_neon_armv7a_neon_vfpv4 ( const uint16_t * arg0, unsigned arg1, uint16_t arg2, unsigned * arg3 );
|
||||
void starch_count_above_u16_aligned_neon_armv7a_neon_vfpv4 ( const uint16_t * arg0, unsigned arg1, uint16_t arg2, unsigned * arg3 );
|
||||
void starch_magnitude_sc16_exact_u32_armv7a_neon_vfpv4 ( const sc16_t * arg0, uint16_t * arg1, unsigned arg2 );
|
||||
void starch_magnitude_sc16_aligned_exact_u32_armv7a_neon_vfpv4 ( const sc16_t * arg0, uint16_t * arg1, unsigned arg2 );
|
||||
void starch_magnitude_sc16_exact_float_armv7a_neon_vfpv4 ( const sc16_t * arg0, uint16_t * arg1, unsigned arg2 );
|
||||
|
|
@ -279,6 +313,10 @@ void starch_magnitude_sc16q11_12bit_table_armv8_neon_simd ( const sc16_t * arg0,
|
|||
void starch_magnitude_sc16q11_aligned_12bit_table_armv8_neon_simd ( const sc16_t * arg0, uint16_t * arg1, unsigned arg2 );
|
||||
void starch_magnitude_sc16q11_neon_vrsqrte_armv8_neon_simd ( const sc16_t * arg0, uint16_t * arg1, unsigned arg2 );
|
||||
void starch_magnitude_sc16q11_aligned_neon_vrsqrte_armv8_neon_simd ( const sc16_t * arg0, uint16_t * arg1, unsigned arg2 );
|
||||
void starch_count_above_u16_generic_armv8_neon_simd ( const uint16_t * arg0, unsigned arg1, uint16_t arg2, unsigned * arg3 );
|
||||
void starch_count_above_u16_aligned_generic_armv8_neon_simd ( const uint16_t * arg0, unsigned arg1, uint16_t arg2, unsigned * arg3 );
|
||||
void starch_count_above_u16_neon_armv8_neon_simd ( const uint16_t * arg0, unsigned arg1, uint16_t arg2, unsigned * arg3 );
|
||||
void starch_count_above_u16_aligned_neon_armv8_neon_simd ( const uint16_t * arg0, unsigned arg1, uint16_t arg2, unsigned * arg3 );
|
||||
void starch_magnitude_sc16_exact_u32_armv8_neon_simd ( const sc16_t * arg0, uint16_t * arg1, unsigned arg2 );
|
||||
void starch_magnitude_sc16_aligned_exact_u32_armv8_neon_simd ( const sc16_t * arg0, uint16_t * arg1, unsigned arg2 );
|
||||
void starch_magnitude_sc16_exact_float_armv8_neon_simd ( const sc16_t * arg0, uint16_t * arg1, unsigned arg2 );
|
||||
|
|
@ -303,6 +341,7 @@ void starch_magnitude_sc16q11_exact_u32_generic ( const sc16_t * arg0, uint16_t
|
|||
void starch_magnitude_sc16q11_exact_float_generic ( const sc16_t * arg0, uint16_t * arg1, unsigned arg2 );
|
||||
void starch_magnitude_sc16q11_11bit_table_generic ( const sc16_t * arg0, uint16_t * arg1, unsigned arg2 );
|
||||
void starch_magnitude_sc16q11_12bit_table_generic ( const sc16_t * arg0, uint16_t * arg1, unsigned arg2 );
|
||||
void starch_count_above_u16_generic_generic ( const uint16_t * arg0, unsigned arg1, uint16_t arg2, unsigned * arg3 );
|
||||
void starch_magnitude_sc16_exact_u32_generic ( const sc16_t * arg0, uint16_t * arg1, unsigned arg2 );
|
||||
void starch_magnitude_sc16_exact_float_generic ( const sc16_t * arg0, uint16_t * arg1, unsigned arg2 );
|
||||
#endif /* STARCH_FLAVOR_GENERIC */
|
||||
|
|
@ -337,6 +376,8 @@ void starch_magnitude_sc16q11_11bit_table_x86_avx2 ( const sc16_t * arg0, uint16
|
|||
void starch_magnitude_sc16q11_aligned_11bit_table_x86_avx2 ( const sc16_t * arg0, uint16_t * arg1, unsigned arg2 );
|
||||
void starch_magnitude_sc16q11_12bit_table_x86_avx2 ( const sc16_t * arg0, uint16_t * arg1, unsigned arg2 );
|
||||
void starch_magnitude_sc16q11_aligned_12bit_table_x86_avx2 ( const sc16_t * arg0, uint16_t * arg1, unsigned arg2 );
|
||||
void starch_count_above_u16_generic_x86_avx2 ( const uint16_t * arg0, unsigned arg1, uint16_t arg2, unsigned * arg3 );
|
||||
void starch_count_above_u16_aligned_generic_x86_avx2 ( const uint16_t * arg0, unsigned arg1, uint16_t arg2, unsigned * arg3 );
|
||||
void starch_magnitude_sc16_exact_u32_x86_avx2 ( const sc16_t * arg0, uint16_t * arg1, unsigned arg2 );
|
||||
void starch_magnitude_sc16_aligned_exact_u32_x86_avx2 ( const sc16_t * arg0, uint16_t * arg1, unsigned arg2 );
|
||||
void starch_magnitude_sc16_exact_float_x86_avx2 ( const sc16_t * arg0, uint16_t * arg1, unsigned arg2 );
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Count the number of samples in a uint16_t buffer that are >= a threshold.
|
||||
*/
|
||||
void STARCH_IMPL(count_above_u16, generic) (const uint16_t *in, unsigned len, uint16_t threshold, unsigned *out_count)
|
||||
{
|
||||
const uint16_t * restrict in_align = STARCH_ALIGNED(in);
|
||||
|
||||
unsigned count = 0;
|
||||
while (len--) {
|
||||
if (in_align[0] >= threshold)
|
||||
++count;
|
||||
++in_align;
|
||||
}
|
||||
|
||||
*out_count = count;
|
||||
}
|
||||
|
||||
#ifdef STARCH_FEATURE_NEON
|
||||
|
||||
#include <arm_neon.h>
|
||||
|
||||
void STARCH_IMPL_REQUIRES(count_above_u16, neon, STARCH_FEATURE_NEON) (const uint16_t *in, unsigned len, uint16_t threshold, unsigned *out_count)
|
||||
{
|
||||
const uint16_t * restrict in_align = STARCH_ALIGNED(in);
|
||||
const uint16x8_t threshold_x8 = vdupq_n_u16(threshold);
|
||||
|
||||
int32x4_t accumulator0 = vdupq_n_s32(0);
|
||||
int32x4_t accumulator1 = vdupq_n_s32(0);
|
||||
|
||||
unsigned len8 = len >> 3;
|
||||
while (len8--) {
|
||||
uint16x8_t mag = vld1q_u16(in_align);
|
||||
int16x8_t compare = vreinterpretq_s16_u16(vcgeq_u16(mag, threshold_x8));
|
||||
accumulator0 = vsubw_s16(accumulator0, vget_low_s16(compare));
|
||||
accumulator1 = vsubw_s16(accumulator1, vget_high_s16(compare));
|
||||
|
||||
in_align += 8;
|
||||
}
|
||||
|
||||
// sum accumulators across all lanes
|
||||
int32x4_t sum2 = vaddq_s32(accumulator0, accumulator1);
|
||||
int32x2_t sum4 = vadd_s32(vget_low_s32(sum2), vget_high_s32(sum2));
|
||||
int32x2_t sum8 = vpadd_s32(sum4, sum4);
|
||||
int32x4_t sum8_x2 = vcombine_s32(sum8, sum8);
|
||||
|
||||
unsigned len1 = len & 7;
|
||||
while (len1--) {
|
||||
uint16x4_t mag = vld1_dup_u16(in_align);
|
||||
int16x4_t compare = vreinterpret_s16_u16(vcge_u16(mag, vget_low_u16(threshold_x8)));
|
||||
sum8_x2 = vsubw_s16(sum8_x2, compare);
|
||||
|
||||
in_align += 1;
|
||||
}
|
||||
|
||||
*out_count = vgetq_lane_s32(sum8_x2, 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
#include <math.h>
|
||||
#include <endian.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdalign.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "compat/compat.h"
|
||||
|
||||
#include "dsp/helpers/tables.h"
|
||||
|
||||
/* Convert UC8 values to unsigned 16-bit magnitudes */
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include <math.h>
|
||||
#include <endian.h>
|
||||
|
||||
#include "compat/compat.h"
|
||||
|
||||
/* Convert (little-endian) SC16 values to unsigned 16-bit magnitudes */
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include <math.h>
|
||||
#include <endian.h>
|
||||
|
||||
#include "compat/compat.h"
|
||||
|
||||
#include "dsp/helpers/tables.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
#include <math.h>
|
||||
#include <endian.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdalign.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "compat/compat.h"
|
||||
|
||||
#include "dsp/helpers/tables.h"
|
||||
|
||||
/* Convert UC8 values to unsigned 16-bit magnitudes */
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ gen.add_function(name = 'magnitude_power_uc8', argtypes = ['const uc8_t *', 'uin
|
|||
gen.add_function(name = 'magnitude_sc16', argtypes = ['const sc16_t *', 'uint16_t *', 'unsigned'], aligned = True)
|
||||
gen.add_function(name = 'magnitude_sc16q11', argtypes = ['const sc16_t *', 'uint16_t *', 'unsigned'], aligned = True)
|
||||
gen.add_function(name = 'mean_power_u16', argtypes = ['const uint16_t *', 'unsigned', 'double *', 'double *'], aligned = True)
|
||||
gen.add_function(name = 'count_above_u16', argtypes = ['const uint16_t *', 'unsigned', 'uint16_t', 'unsigned *'], aligned = True)
|
||||
|
||||
gen.add_feature(name='neon', description='ARM NEON')
|
||||
|
||||
|
|
|
|||
217
dump1090.c
217
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,6 +121,31 @@ 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;
|
||||
Modes.adaptive_burst_loud_runlength = 10;
|
||||
Modes.adaptive_burst_loud_rate = 5.0;
|
||||
Modes.adaptive_burst_quiet_runlength = 10;
|
||||
Modes.adaptive_burst_quiet_rate = 5.0;
|
||||
|
||||
Modes.adaptive_range_control = false;
|
||||
Modes.adaptive_range_alpha = 2.0 / (5 + 1);
|
||||
Modes.adaptive_range_percentile = 40;
|
||||
Modes.adaptive_range_change_delay = 10;
|
||||
Modes.adaptive_range_scan_delay = 300;
|
||||
Modes.adaptive_range_rescan_delay = 3600;
|
||||
|
||||
sdrInitConfig();
|
||||
}
|
||||
//
|
||||
|
|
@ -287,6 +311,7 @@ static void showDSP()
|
|||
SHOW(magnitude_sc16);
|
||||
SHOW(magnitude_sc16q11);
|
||||
SHOW(mean_power_u16);
|
||||
SHOW(count_above_u16);
|
||||
|
||||
#undef SHOW
|
||||
|
||||
|
|
@ -300,60 +325,111 @@ static void showHelp(void)
|
|||
sdrShowHelp();
|
||||
|
||||
printf(
|
||||
" Common options\n"
|
||||
" Output modes\n"
|
||||
"\n"
|
||||
"--gain <db> Set gain (default: max gain. Use -10 for auto-gain)\n"
|
||||
"--freq <hz> Set frequency (default: 1090 Mhz)\n"
|
||||
"--interactive Interactive mode refreshing data on screen. Implies --throttle\n"
|
||||
"--interactive-ttl <sec> Remove from list if idle for <sec> (default: 60)\n"
|
||||
"--interactive-show-distance Show aircraft distance and bearing instead of lat/lon\n"
|
||||
" (requires --lat and --lon)\n"
|
||||
"--interactive-distance-units Distance units ('km', 'sm', 'nm') (default: 'nm')\n"
|
||||
"--interactive-callsign-filter Only callsigns that match the prefix or regex will be displayed\n"
|
||||
// ------ 80 char limit ----------------------------------------------------------|
|
||||
"--raw Show only messages hex values\n"
|
||||
"--net Enable networking with default ports unless overridden\n"
|
||||
"--modeac Enable decoding of SSR Modes 3/A & 3/C\n"
|
||||
"--no-modeac-auto Don't enable Mode A/C if requested by a Beast connection\n"
|
||||
"--mlat display raw messages in Beast ascii mode\n"
|
||||
"--onlyaddr Show only ICAO addresses (testing purposes)\n"
|
||||
"--metric Use metric units (meters, km/h, ...)\n"
|
||||
"--gnss Show altitudes as HAE/GNSS when available\n"
|
||||
"--quiet Disable output to stdout. Use for daemon applications\n"
|
||||
"--show-only <addr> Show only messages from the given ICAO on stdout\n"
|
||||
"--snip <level> Strip IQ file removing samples < level\n"
|
||||
"\n"
|
||||
" Decoder settings\n"
|
||||
"\n"
|
||||
// ------ 80 char limit ----------------------------------------------------------|
|
||||
"--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"
|
||||
" (use with caution!)\n"
|
||||
"--no-fix Disable error correction using CRC\n"
|
||||
"--no-fix-df Disable error correction of the DF message field\n"
|
||||
" (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"
|
||||
"--lat <latitude> Reference/receiver latitude for surface positions\n"
|
||||
"--lon <longitude> Reference/receiver longitude for surface positions\n"
|
||||
"--max-range <distance> Absolute maximum range for position decoding (in NM)\n"
|
||||
"\n"
|
||||
// ------ 80 char limit ----------------------------------------------------------|
|
||||
" Adaptive gain\n"
|
||||
"\n"
|
||||
"--adaptive-burst Adjust gain for too-loud message bursts\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"
|
||||
"--adaptive-burst-loud-rate <r> Set burst rate for gain decrease\n"
|
||||
"--adaptive-burst-loud-runlength <l> Set burst runlength for gain decrease\n"
|
||||
"--adaptive-burst-quiet-rate <r> Set burst rate for gain increase\n"
|
||||
"--adaptive-burst-quiet-runlength <l> Set burst runlength for gain increase\n"
|
||||
"--adaptive-range Adjust gain for target dynamic range\n"
|
||||
"--adaptive-range-target <db> Set target dynamic range in dB\n"
|
||||
"--adaptive-range-alpha <a> Set dynamic range noise smoothing factor\n"
|
||||
" (0..1, smaller=more smoothing)\n"
|
||||
"--adaptive-range-percentile <p> Set dynamic range noise percentile\n"
|
||||
"--adaptive-range-change-delay <s> Set delay after changing gain before\n"
|
||||
" resuming dynamic range control (seconds)\n"
|
||||
"--adaptive-range-scan-delay <s> Set scan interval for dynamic range\n"
|
||||
" gain scanning following a gain decrease\n"
|
||||
" due to an increase in noise (seconds)\n"
|
||||
"--adaptive-range-rescan-delay <s> Set periodic rescan interval for dynamic\n"
|
||||
" range 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"
|
||||
"\n"
|
||||
"--net Enable networking with default ports unless overridden\n"
|
||||
"--no-modeac-auto Don't enable Mode A/C if requested by a net connection\n"
|
||||
"--net-only Enable just networking, no RTL device or file used\n"
|
||||
"--net-bind-address <ip> IP address to bind to (default: Any; Use 127.0.0.1 for private)\n"
|
||||
"--net-bind-address <ip> IP address to bind to (use 127.0.0.1 for private)\n"
|
||||
"--net-ri-port <ports> TCP raw input listen ports (default: 30001)\n"
|
||||
"--net-ro-port <ports> TCP raw output listen ports (default: 30002)\n"
|
||||
"--net-sbs-port <ports> TCP BaseStation output listen ports (default: 30003)\n"
|
||||
"--net-bi-port <ports> TCP Beast input listen ports (default: 30004,30104)\n"
|
||||
"--net-bo-port <ports> TCP Beast output listen ports (default: 30005)\n"
|
||||
"--net-stratux-port <ports> TCP Stratux output listen ports (default: disabled)\n"
|
||||
"--net-stratux-port <ports> TCP Stratux output listen ports (default: disabled)\n"
|
||||
"--net-ro-size <size> TCP output minimum size (default: 0)\n"
|
||||
"--net-ro-interval <rate> TCP output memory flush rate in seconds (default: 0)\n"
|
||||
"--net-heartbeat <rate> TCP heartbeat rate in seconds (default: 60 sec; 0 to disable)\n"
|
||||
"--net-heartbeat <rate> TCP heartbeat rate in seconds\n"
|
||||
" (default: 60 sec; 0 to disable)\n"
|
||||
"--net-buffer <n> TCP buffer size 64Kb * (2^n) (default: n=0, 64Kb)\n"
|
||||
"--net-verbatim Make Beast-format output connections default to verbatim mode\n"
|
||||
" (forward all messages, without applying CRC corrections)\n"
|
||||
"--forward-mlat Allow forwarding of received mlat results to output ports\n"
|
||||
"--lat <latitude> Reference/receiver latitude for surface posn (opt)\n"
|
||||
"--lon <longitude> Reference/receiver longitude for surface posn (opt)\n"
|
||||
"--max-range <distance> Absolute maximum range for position decoding (in nm, default: 300)\n"
|
||||
"--fix Enable single-bit error correction using CRC\n"
|
||||
"--fix-2bit Enable two-bit error correction using CRC (use with caution)\n"
|
||||
"--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"
|
||||
"--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"
|
||||
"--net-verbatim Make output connections default to verbatim mode\n"
|
||||
" (forward all messages without correction)\n"
|
||||
"--forward-mlat Allow forwarding of received mlat results\n"
|
||||
"\n"
|
||||
// ------ 80 char limit ----------------------------------------------------------|
|
||||
" Stats and json output\n"
|
||||
"\n"
|
||||
"--stats Show stats summary at exit.\n"
|
||||
"--stats-every <seconds> Show and reset stats every <seconds> seconds\n"
|
||||
"--onlyaddr Show only ICAO addresses (testing purposes)\n"
|
||||
"--metric Use metric units (meters, km/h, ...)\n"
|
||||
"--gnss Show altitudes as HAE/GNSS (with H suffix) when available\n"
|
||||
"--snip <level> Strip IQ file removing samples < level\n"
|
||||
"--quiet Disable output to stdout. Use for daemon applications\n"
|
||||
"--show-only <addr> Show only messages from the given ICAO on stdout\n"
|
||||
"--write-json <dir> Periodically write json output to <dir> (for serving by a separate webserver)\n"
|
||||
"--stats-range Collect/show range histogram\n"
|
||||
"--write-json <dir> Periodically write json output to <dir>\n"
|
||||
" (for serving by a separate webserver)\n"
|
||||
"--write-json-every <t> Write json aircraft output every t seconds (default 1)\n"
|
||||
"--json-stats-every <t> Write json stats output every t seconds (default 60)\n"
|
||||
"--json-location-accuracy <n> Accuracy of receiver location in json metadata: 0=no location, 1=approximate, 2=exact\n"
|
||||
#if 0
|
||||
"--dcfilter Apply a 1Hz DC filter to input data (requires more CPU)\n"
|
||||
#endif
|
||||
"--json-location-accuracy <n> Accuracy of receiver location in json metadata\n"
|
||||
" (0=no location, 1=approximate, 2=exact)\n"
|
||||
"\n"
|
||||
" Interactive mode\n"
|
||||
"\n"
|
||||
"--interactive Interactive mode refreshing data on screen.\n"
|
||||
" Implies --throttle\n"
|
||||
"--interactive-ttl <sec> Remove from list if idle for <sec>\n"
|
||||
"--interactive-show-distance Show aircraft distance and bearing\n"
|
||||
" (requires --lat and --lon)\n"
|
||||
"--interactive-distance-units <u> Distance units ('km', 'sm', 'nm')\n"
|
||||
"--interactive-callsign-filter <r> Filter rows by callsign against regex\n"
|
||||
"\n"
|
||||
" Misc\n"
|
||||
"\n"
|
||||
"--wisdom <path> Read DSP wisdom from given path\n"
|
||||
"--version Show version, build and DSP options\n"
|
||||
"--help Show this help\n"
|
||||
|
|
@ -362,7 +438,8 @@ static void showHelp(void)
|
|||
|
||||
// Accumulate stats data from stats_current to stats_periodic, stats_alltime and stats_latest;
|
||||
// reset stats_current
|
||||
static void flush_stats(uint64_t now)
|
||||
void flush_stats(uint64_t now);
|
||||
void flush_stats(uint64_t now)
|
||||
{
|
||||
add_stats(&Modes.stats_current, &Modes.stats_periodic, &Modes.stats_periodic);
|
||||
add_stats(&Modes.stats_current, &Modes.stats_alltime, &Modes.stats_alltime);
|
||||
|
|
@ -533,7 +610,7 @@ int main(int argc, char **argv) {
|
|||
} else if ( (!strcmp(argv[j], "--device") || !strcmp(argv[j], "--device-index")) && more) {
|
||||
Modes.dev_name = strdup(argv[++j]);
|
||||
} else if (!strcmp(argv[j],"--gain") && more) {
|
||||
Modes.gain = (int) (atof(argv[++j])*10); // Gain is in tens of DBs
|
||||
Modes.gain = atof(argv[++j]);
|
||||
} else if (!strcmp(argv[j],"--dcfilter")) {
|
||||
#if 0
|
||||
Modes.dc_filter = 1;
|
||||
|
|
@ -547,6 +624,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")) {
|
||||
|
|
@ -691,6 +770,40 @@ int main(int argc, char **argv) {
|
|||
"Failed to read wisdom file %s: %s\n", argv[j], strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
} else if (!strcmp(argv[j], "--adaptive-min-gain") && more) {
|
||||
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) {
|
||||
Modes.adaptive_burst_alpha = atof(argv[++j]);
|
||||
} else if (!strcmp(argv[j], "--adaptive-burst-change-delay") && more) {
|
||||
Modes.adaptive_burst_change_delay = atoi(argv[++j]);
|
||||
} else if (!strcmp(argv[j], "--adaptive-burst-loud-rate") && more) {
|
||||
Modes.adaptive_burst_loud_rate = atof(argv[++j]);
|
||||
} else if (!strcmp(argv[j], "--adaptive-burst-loud-runlength") && more) {
|
||||
Modes.adaptive_burst_loud_runlength = atoi(argv[++j]);
|
||||
} else if (!strcmp(argv[j], "--adaptive-burst-quiet-rate") && more) {
|
||||
Modes.adaptive_burst_quiet_rate = atof(argv[++j]);
|
||||
} else if (!strcmp(argv[j], "--adaptive-burst-quiet-runlength") && more) {
|
||||
Modes.adaptive_burst_quiet_runlength = atoi(argv[++j]);
|
||||
} else if (!strcmp(argv[j], "--adaptive-range")) {
|
||||
Modes.adaptive_range_control = true;
|
||||
} else if (!strcmp(argv[j], "--adaptive-range-alpha") && more) {
|
||||
Modes.adaptive_range_alpha = atof(argv[++j]);
|
||||
} else if (!strcmp(argv[j], "--adaptive-range-percentile") && more) {
|
||||
Modes.adaptive_range_percentile = atoi(argv[++j]);
|
||||
} else if (!strcmp(argv[j], "--adaptive-range-target") && more) {
|
||||
Modes.adaptive_range_target = atof(argv[++j]);
|
||||
} else if (!strcmp(argv[j], "--adaptive-range-change-delay") && more) {
|
||||
Modes.adaptive_range_change_delay = atoi(argv[++j]);
|
||||
} else if (!strcmp(argv[j], "--adaptive-range-scan-delay") && more) {
|
||||
Modes.adaptive_range_scan_delay = atoi(argv[++j]);
|
||||
} else if (!strcmp(argv[j], "--adaptive-range-rescan-delay") && more) {
|
||||
Modes.adaptive_range_rescan_delay = atoi(argv[++j]);
|
||||
} else if (sdrHandleOption(argc, argv, &j)) {
|
||||
/* handled */
|
||||
} else {
|
||||
|
|
@ -737,6 +850,8 @@ int main(int argc, char **argv) {
|
|||
for (j = 0; j < 15; ++j)
|
||||
Modes.stats_1min[j].start = Modes.stats_1min[j].end = Modes.stats_current.start;
|
||||
|
||||
adaptive_init();
|
||||
|
||||
// write initial json files so they're not missing
|
||||
writeJsonToFile("receiver.json", generateReceiverJson);
|
||||
writeJsonToFile("stats.json", generateStatsJson);
|
||||
|
|
@ -758,7 +873,7 @@ int main(int argc, char **argv) {
|
|||
nanosleep(&slp, NULL);
|
||||
}
|
||||
} else {
|
||||
int watchdogCounter = 10; // about 1 second
|
||||
int watchdogCounter = 300; // about 30 seconds
|
||||
|
||||
// Create the thread that will read the data from the device.
|
||||
pthread_create(&Modes.reader_thread, NULL, readerThreadEntryPoint, NULL);
|
||||
|
|
@ -786,12 +901,12 @@ int main(int argc, char **argv) {
|
|||
fifo_release(buf);
|
||||
|
||||
// We got something so reset the watchdog
|
||||
watchdogCounter = 10;
|
||||
watchdogCounter = 300;
|
||||
} else {
|
||||
// Nothing to process this time around.
|
||||
if (--watchdogCounter <= 0) {
|
||||
log_with_timestamp("No data received from the SDR for a long time, it may have wedged");
|
||||
watchdogCounter = 600;
|
||||
log_with_timestamp("No samples received from the SDR for a long time. Maybe the hardware is wedged? Giving up.");
|
||||
Modes.exit = 2; // abnormal exit
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -801,8 +916,14 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
log_with_timestamp("Waiting for receive thread termination");
|
||||
sdrStop(); // tell reader thread to wake up and exit
|
||||
fifo_halt(); // Reader thread should do this anyway, but just in case..
|
||||
pthread_join(Modes.reader_thread,NULL); // Wait on reader thread exit
|
||||
|
||||
// Wait on reader thread exit
|
||||
if (join_thread(Modes.reader_thread, NULL, 30000) == ETIMEDOUT) {
|
||||
log_with_timestamp("Receive thread did not shut down cleanly in 30 seconds, aborting.");
|
||||
abort(); // Can't complete cleanup while the receive thread is active; bail out.
|
||||
}
|
||||
}
|
||||
|
||||
interactiveCleanup();
|
||||
|
|
|
|||
72
dump1090.h
72
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 -100 // 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
|
||||
|
|
@ -272,6 +293,7 @@ typedef enum {
|
|||
#include "convert.h"
|
||||
#include "sdr.h"
|
||||
#include "fifo.h"
|
||||
#include "adaptive.h"
|
||||
|
||||
//======================== structure declarations =========================
|
||||
|
||||
|
|
@ -296,9 +318,9 @@ struct _Modes { // Internal state
|
|||
// Sample conversion
|
||||
int dc_filter; // should we apply a DC filter?
|
||||
|
||||
// RTLSDR
|
||||
// RTLSDR and some other SDRs
|
||||
char * dev_name;
|
||||
int gain;
|
||||
float gain; // value in dB, or MODES_AUTO_GAIN, or MODES_MAX_GAIN
|
||||
int freq;
|
||||
|
||||
// Networking
|
||||
|
|
@ -325,6 +347,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
|
||||
|
|
@ -362,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 {
|
||||
|
|
@ -387,6 +411,28 @@ struct _Modes { // Internal state
|
|||
int stats_newest_1min; // Index into stats_1min of the most recent 1-minute window
|
||||
struct stats stats_5min; // Accumulated stats from the last 5 complete 1-minute windows
|
||||
struct stats stats_15min; // Accumulated stats from the last 15 complete 1-minute windows
|
||||
|
||||
// Adaptive gain config
|
||||
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;
|
||||
float adaptive_burst_loud_rate;
|
||||
unsigned adaptive_burst_loud_runlength;
|
||||
float adaptive_burst_quiet_rate;
|
||||
unsigned adaptive_burst_quiet_runlength;
|
||||
|
||||
bool adaptive_range_control;
|
||||
float adaptive_range_alpha;
|
||||
unsigned adaptive_range_percentile;
|
||||
float adaptive_range_target;
|
||||
unsigned adaptive_range_change_delay;
|
||||
unsigned adaptive_range_scan_delay;
|
||||
unsigned adaptive_range_rescan_delay;
|
||||
};
|
||||
|
||||
extern struct _Modes Modes;
|
||||
|
|
@ -588,6 +634,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:
|
||||
|
|
|
|||
111
mode_s.c
111
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;
|
||||
|
||||
|
|
@ -1652,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:
|
||||
|
|
@ -1666,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";
|
||||
}
|
||||
|
|
@ -1719,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) {
|
||||
|
|
@ -2184,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);
|
||||
}
|
||||
|
|
|
|||
348
net_io.c
348
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");
|
||||
}
|
||||
|
||||
|
|
@ -1290,6 +1300,36 @@ static int hexDigitVal(int c) {
|
|||
else if (c >= 'a' && c <= 'f') return c-'a'+10;
|
||||
else return -1;
|
||||
}
|
||||
|
||||
|
||||
// decode 12 hex digits as a 48-bit timestamp
|
||||
static bool timestampFromHex(const char *hex, uint64_t *timestamp)
|
||||
{
|
||||
uint64_t ts = 0;
|
||||
for (unsigned i = 0; i < 12; ++i) {
|
||||
int v = hexDigitVal(hex[i]);
|
||||
if (v < 0)
|
||||
return false;
|
||||
ts = (ts << 4) | v;
|
||||
}
|
||||
|
||||
*timestamp = ts;
|
||||
return true;
|
||||
}
|
||||
|
||||
// decode 2 hex digits as a signal level
|
||||
static bool signalFromHex(const char *hex, double *signal)
|
||||
{
|
||||
int d1 = hexDigitVal(hex[0]);
|
||||
int d2 = hexDigitVal(hex[1]);
|
||||
if (d1 < 0 || d2 < 0)
|
||||
return false;
|
||||
|
||||
double sig = ((d1 << 4) | d2) / 255.0;
|
||||
*signal = sig * sig;
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
//=========================================================================
|
||||
//
|
||||
|
|
@ -1331,26 +1371,50 @@ static int decodeHexMessage(struct client *c, char *hex) {
|
|||
// and some AVR records that we can understand
|
||||
if (hex[l-1] != ';') {return (0);} // not complete - abort
|
||||
|
||||
switch(hex[0]) {
|
||||
case '<': {
|
||||
mm.signalLevel = ((hexDigitVal(hex[13])<<4) | hexDigitVal(hex[14])) / 255.0;
|
||||
mm.signalLevel = mm.signalLevel * mm.signalLevel;
|
||||
hex += 15; l -= 16; // Skip <, timestamp and siglevel, and ;
|
||||
break;}
|
||||
switch (hex[0]) {
|
||||
case '<':
|
||||
// [0] '<'
|
||||
// [1..12] timestamp
|
||||
// [13..14] signal level
|
||||
// [15..l-2] data
|
||||
// [l-1] ';'
|
||||
if (l < 18)
|
||||
return 0; // truncated
|
||||
if (!timestampFromHex(hex + 1, &mm.timestampMsg))
|
||||
return 0; // malformed timestamp
|
||||
if (!signalFromHex(hex + 13, &mm.signalLevel))
|
||||
return 0; // malformed signal level
|
||||
hex += 15;
|
||||
l -= 16;
|
||||
break;
|
||||
|
||||
case '@': // No CRC check
|
||||
case '%': { // CRC is OK
|
||||
hex += 13; l -= 14; // Skip @,%, and timestamp, and ;
|
||||
break;}
|
||||
case '%': // CRC is OK
|
||||
// [0] '@' or '%'
|
||||
// [1..12] timestamp
|
||||
// [13..l-2] data
|
||||
// [l-1] ';'
|
||||
if (l < 16)
|
||||
return 0; // truncated
|
||||
if (!timestampFromHex(hex + 1, &mm.timestampMsg))
|
||||
return 0; // malformed timestamp
|
||||
hex += 13;
|
||||
l -= 14;
|
||||
break;
|
||||
|
||||
case '*':
|
||||
case ':': {
|
||||
hex++; l-=2; // Skip * and ;
|
||||
break;}
|
||||
case ':':
|
||||
// [0] '*' or ':'
|
||||
// [1..l-2] data
|
||||
// [l-1] ';'
|
||||
if (l < 4)
|
||||
return 0; // truncated
|
||||
hex++;
|
||||
l -= 2;
|
||||
break;
|
||||
|
||||
default: {
|
||||
return (0); // We don't know what this is, so abort
|
||||
break;}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( (l != (MODEAC_MSG_BYTES * 2))
|
||||
|
|
@ -1604,6 +1668,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 +1794,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\":");
|
||||
|
|
@ -1803,64 +1901,90 @@ static char * appendStatsJson(char *p,
|
|||
p = safe_snprintf(p, end, "]}");
|
||||
}
|
||||
|
||||
{
|
||||
uint64_t demod_cpu_millis = (uint64_t)st->demod_cpu.tv_sec*1000UL + st->demod_cpu.tv_nsec/1000000UL;
|
||||
uint64_t reader_cpu_millis = (uint64_t)st->reader_cpu.tv_sec*1000UL + st->reader_cpu.tv_nsec/1000000UL;
|
||||
uint64_t background_cpu_millis = (uint64_t)st->background_cpu.tv_sec*1000UL + st->background_cpu.tv_nsec/1000000UL;
|
||||
uint64_t demod_cpu_millis = (uint64_t)st->demod_cpu.tv_sec*1000UL + st->demod_cpu.tv_nsec/1000000UL;
|
||||
uint64_t reader_cpu_millis = (uint64_t)st->reader_cpu.tv_sec*1000UL + st->reader_cpu.tv_nsec/1000000UL;
|
||||
uint64_t background_cpu_millis = (uint64_t)st->background_cpu.tv_sec*1000UL + st->background_cpu.tv_nsec/1000000UL;
|
||||
|
||||
p = safe_snprintf(p, end,
|
||||
",\"cpr\":{\"surface\":%u"
|
||||
",\"airborne\":%u"
|
||||
",\"global_ok\":%u"
|
||||
",\"global_bad\":%u"
|
||||
",\"global_range\":%u"
|
||||
",\"global_speed\":%u"
|
||||
",\"global_skipped\":%u"
|
||||
",\"local_ok\":%u"
|
||||
",\"local_aircraft_relative\":%u"
|
||||
",\"local_receiver_relative\":%u"
|
||||
",\"local_skipped\":%u"
|
||||
",\"local_range\":%u"
|
||||
",\"local_speed\":%u"
|
||||
",\"filtered\":%u}"
|
||||
",\"altitude_suppressed\":%u"
|
||||
",\"cpu\":{\"demod\":%llu,\"reader\":%llu,\"background\":%llu}"
|
||||
",\"tracks\":{\"all\":%u"
|
||||
",\"single_message\":%u"
|
||||
",\"unreliable\":%u}"
|
||||
",\"messages\":%u",
|
||||
st->cpr_surface,
|
||||
st->cpr_airborne,
|
||||
st->cpr_global_ok,
|
||||
st->cpr_global_bad,
|
||||
st->cpr_global_range_checks,
|
||||
st->cpr_global_speed_checks,
|
||||
st->cpr_global_skipped,
|
||||
st->cpr_local_ok,
|
||||
st->cpr_local_aircraft_relative,
|
||||
st->cpr_local_receiver_relative,
|
||||
st->cpr_local_skipped,
|
||||
st->cpr_local_range_checks,
|
||||
st->cpr_local_speed_checks,
|
||||
st->cpr_filtered,
|
||||
st->suppressed_altitude_messages,
|
||||
(unsigned long long)demod_cpu_millis,
|
||||
(unsigned long long)reader_cpu_millis,
|
||||
(unsigned long long)background_cpu_millis,
|
||||
st->unique_aircraft,
|
||||
st->single_message_aircraft,
|
||||
st->unreliable_aircraft,
|
||||
st->messages_total);
|
||||
|
||||
for (i = 0; i < 32; ++i) {
|
||||
if (i == 0)
|
||||
p = safe_snprintf(p, end, ",\"messages_by_df\":[%u", st->messages_by_df[i]);
|
||||
else
|
||||
p = safe_snprintf(p, end, ",%u", st->messages_by_df[i]);
|
||||
}
|
||||
p = safe_snprintf(p, end, "]");
|
||||
|
||||
if (st->adaptive_valid) {
|
||||
p = safe_snprintf(p, end,
|
||||
",\"cpr\":{\"surface\":%u"
|
||||
",\"airborne\":%u"
|
||||
",\"global_ok\":%u"
|
||||
",\"global_bad\":%u"
|
||||
",\"global_range\":%u"
|
||||
",\"global_speed\":%u"
|
||||
",\"global_skipped\":%u"
|
||||
",\"local_ok\":%u"
|
||||
",\"local_aircraft_relative\":%u"
|
||||
",\"local_receiver_relative\":%u"
|
||||
",\"local_skipped\":%u"
|
||||
",\"local_range\":%u"
|
||||
",\"local_speed\":%u"
|
||||
",\"filtered\":%u}"
|
||||
",\"altitude_suppressed\":%u"
|
||||
",\"cpu\":{\"demod\":%llu,\"reader\":%llu,\"background\":%llu}"
|
||||
",\"tracks\":{\"all\":%u"
|
||||
",\"single_message\":%u"
|
||||
",\"unreliable\":%u}"
|
||||
",\"messages\":%u",
|
||||
st->cpr_surface,
|
||||
st->cpr_airborne,
|
||||
st->cpr_global_ok,
|
||||
st->cpr_global_bad,
|
||||
st->cpr_global_range_checks,
|
||||
st->cpr_global_speed_checks,
|
||||
st->cpr_global_skipped,
|
||||
st->cpr_local_ok,
|
||||
st->cpr_local_aircraft_relative,
|
||||
st->cpr_local_receiver_relative,
|
||||
st->cpr_local_skipped,
|
||||
st->cpr_local_range_checks,
|
||||
st->cpr_local_speed_checks,
|
||||
st->cpr_filtered,
|
||||
st->suppressed_altitude_messages,
|
||||
(unsigned long long)demod_cpu_millis,
|
||||
(unsigned long long)reader_cpu_millis,
|
||||
(unsigned long long)background_cpu_millis,
|
||||
st->unique_aircraft,
|
||||
st->single_message_aircraft,
|
||||
st->unreliable_aircraft,
|
||||
st->messages_total);
|
||||
|
||||
for (i = 0; i < 32; ++i) {
|
||||
if (i == 0)
|
||||
p = safe_snprintf(p, end, ",\"messages_by_df\":[%u", st->messages_by_df[i]);
|
||||
else
|
||||
p = safe_snprintf(p, end, ",%u", st->messages_by_df[i]);
|
||||
",\"adaptive\":"
|
||||
"{\"gain_db\":%.1f"
|
||||
",\"dynamic_range_limit_db\":%.1f"
|
||||
",\"gain_changes\":%u"
|
||||
",\"loud_undecoded\":%u"
|
||||
",\"loud_decoded\":%u"
|
||||
",\"noise_dbfs\":%.1f"
|
||||
",\"gain_seconds\":[",
|
||||
sdrGetGainDb(st->adaptive_gain),
|
||||
sdrGetGainDb(st->adaptive_range_gain_limit),
|
||||
st->adaptive_gain_changes,
|
||||
st->adaptive_loud_undecoded,
|
||||
st->adaptive_loud_decoded,
|
||||
st->adaptive_noise_dbfs);
|
||||
bool first = true;
|
||||
for (unsigned i = 0; i < STATS_GAIN_COUNT; ++i) {
|
||||
if (st->adaptive_gain_seconds[i] > 0) {
|
||||
p = safe_snprintf(p, end, "%s[%.1f,%u]",
|
||||
first ? "" : ",",
|
||||
sdrGetGainDb(i), st->adaptive_gain_seconds[i]);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
p = safe_snprintf(p, end, "]}");
|
||||
}
|
||||
|
||||
p = safe_snprintf(p, end, "}");
|
||||
return p;
|
||||
}
|
||||
|
||||
|
|
@ -1967,6 +2091,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*))
|
||||
{
|
||||
|
|
@ -1984,8 +2132,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);
|
||||
|
|
@ -1995,15 +2145,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;
|
||||
|
||||
|
|
@ -2231,7 +2389,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)
|
||||
{
|
||||
|
|
@ -2326,6 +2484,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;
|
||||
|
|
@ -2500,7 +2675,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;
|
||||
|
|
@ -2602,10 +2783,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().
|
||||
|
|
|
|||
|
|
@ -35,21 +35,20 @@ FILES=$(find $TOP -mindepth 1 -maxdepth 1 -name .git -prune -o -name 'debian*' -
|
|||
mkdir -p $OUT
|
||||
cp -a $FILES $OUT
|
||||
cp -a $TOP/debian $OUT
|
||||
[ -d $TOP/debian-$DIST ] && cp -a $TOP/debian-$DIST/* $OUT/debian/
|
||||
|
||||
case "$DIST" in
|
||||
jessie)
|
||||
cp -a $TOP/debian-jessie/* $OUT/debian/
|
||||
echo "Updating changelog for jessie backport build" >&2
|
||||
dch --changelog $OUT/debian/changelog --local ~bpo8+ --force-distribution --distribution jessie-backports "Automated backport build for jessie"
|
||||
;;
|
||||
|
||||
stretch)
|
||||
cp -a $TOP/debian-stretch/* $OUT/debian/
|
||||
echo "Updating changelog for stretch backport build" >&2
|
||||
dch --changelog $OUT/debian/changelog --local ~bpo9+ --force-distribution --distribution stretch-backports "Automated backport build for jessie"
|
||||
;;
|
||||
|
||||
buster)
|
||||
echo "Updating changelog for buster backport build" >&2
|
||||
dch --changelog $OUT/debian/changelog --local ~bpo10+ --force-distribution --distribution buster-backports "Automated backport build for buster"
|
||||
;;
|
||||
|
||||
bullseye)
|
||||
;;
|
||||
|
||||
*)
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
# SkyAware 4.0 Features
|
||||
# SkyAware Features
|
||||
|
||||
## Customize display via URL query strings
|
||||
|
||||
Syntax: <ip_address>/dump1090-fa/?parameter=value
|
||||
Syntax: <ip_address>/skyaware/?parameter=value
|
||||
|
||||
Examples:
|
||||
|
||||
http://192.0.0.1/dump1090-fa/?sidebar=hide
|
||||
http://<ip_address>/skyaware/?sidebar=hide
|
||||
|
||||
http://192.0.0.1/dump1090-fa/?altitudeChart=hide
|
||||
http://<ip_address>/skyaware/?altitudeChart=hide
|
||||
|
||||
http://192.0.0.1/dump1090-fa/?rangeRings=hide
|
||||
http://<ip_address>/skyaware/?rangeRings=hide
|
||||
|
||||
http://192.0.0.1/dump1090-fa/?ringCount=3?ringBaseDistance=100?ringInterval=50
|
||||
http://<ip_address>/skyaware/?ringCount=3&ringBaseDistance=100&ringInterval=50
|
||||
|
||||
| Parameter | Possible Values |
|
||||
| :---------: | :---------: |
|
||||
|
|
@ -31,7 +31,7 @@ Examples:
|
|||
| rangeRings | show/hide |
|
||||
| ringCount | integer |
|
||||
| ringBaseDistance | integer |
|
||||
| ringInteval | integer |
|
||||
| ringInterval | integer |
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -23,9 +23,8 @@ DisplayUnits = "nautical";
|
|||
// degrees.
|
||||
|
||||
// Default center of the map.
|
||||
// 39.234 | -103.697 - Limon, CO
|
||||
DefaultCenterLat = 39.234;
|
||||
DefaultCenterLon = -103.697;
|
||||
DefaultCenterLat = 45.0;
|
||||
DefaultCenterLon = 9.0;
|
||||
// The google maps zoom level, 0 - 16, lower is further out
|
||||
DefaultZoomLvl = 7;
|
||||
|
||||
|
|
@ -126,3 +125,8 @@ BingMapsAPIKey = null;
|
|||
// This is not polished yet (and so is disabled by default),
|
||||
// currently it's just a data dump of the new fields with no UX work.
|
||||
ExtendedData = false;
|
||||
|
||||
DefaultMaxAltitudeFilter = 65000
|
||||
DefaultMinAltitudeFilter = 0
|
||||
DefaultMaxSpeedFilter = 1000
|
||||
DefaultMinSpeedFilter = 0
|
||||
|
|
@ -1 +0,0 @@
|
|||
Placeholder for the JSON output data directory.
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -1 +1 @@
|
|||
{"01001":{"r":"V5-NAM","t":"F900"},"01028":{"r":"V5-NMF","t":"A343"},"01029":{"r":"V5-NME","t":"A343"},"02031":{"r":"E3-AAQ","t":"B762"}}
|
||||
{"01001":{"r":"V5-NAM","t":"F900"},"01028":{"r":"V5-NMF","t":"A343"},"01029":{"r":"V5-NME","t":"A343"},"0103F":{"r":"V5-GON"},"02031":{"r":"E3-AAQ","t":"B762"}}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -1 +1 @@
|
|||
{"00007":{"r":"EK-32011","t":"A319"},"0000A":{"r":"EK-32002","t":"A320"},"0000B":{"r":"EK-32003","t":"A320"},"0000C":{"r":"EK-32008","t":"A320"},"00010":{"r":"EK-73736","t":"B735"},"00013":{"r":"EK-11001","t":"AN12"},"00023":{"r":"EK-73786","t":"B737"},"0002F":{"r":"EK-12104","t":"AN12"},"0003C":{"r":"EK-RA01","t":"A319"},"0004A":{"r":"EK-32007","t":"A319"},"00059":{"r":"EK-95015","t":"SU95"},"0005A":{"r":"EK-95016","t":"SU95"},"0005F":{"r":"EW-412TH","t":"IL76"},"00076":{"r":"EK-74723","t":"B742"},"00079":{"r":"EK-74798","t":"B742"},"00087":{"r":"EK-74799","t":"B742"},"0009D":{"r":"EK-73775","t":"B735"},"0009F":{"r":"EK-73772","t":"B735"},"00801":{"r":"4K8888","t":"A319"},"00803":{"r":"4KAZ03","t":"A319"},"00804":{"r":"4KAZ04","t":"A319"},"00805":{"r":"4KAZ05","t":"A319"},"00806":{"r":"4KAI06","t":"GLF5"},"00807":{"r":"4KAI07","t":"A320"},"00808":{"r":"4K-MEK8","t":"GLF5"},"0080C":{"r":"4KAZ12","t":"B752"},"00826":{"r":"4K-AZ38","t":"B752"},"00828":{"r":"4KAZ40","t":"IL76"},"00829":{"r":"4KAZ41","t":"IL76"},"0082B":{"r":"4K-AZ43","t":"B752"},"00836":{"r":"4K-AZ54","t":"A320"},"00838":{"r":"4K-AZ56","t":"AN12"},"0083C":{"r":"4KAZ60","t":"IL76"},"00840":{"r":"4KAZ64","t":"E190"},"00841":{"r":"4KAZ65","t":"E190"},"00842":{"r":"4KAZ66","t":"E190"},"00843":{"r":"4KAZ67","t":"E190"},"0084D":{"r":"4KAZ77","t":"A320"},"0084E":{"r":"4KAZ78","t":"A320"},"0084F":{"r":"4KAZ79","t":"A320"},"00850":{"r":"4KAZ80","t":"A320"},"00851":{"r":"4KAZ81","t":"B763"},"00852":{"r":"4KAZ82","t":"B763"},"00853":{"r":"4KAZ83","t":"A320"},"00854":{"r":"4KAZ84","t":"A320"},"00855":{"r":"4KAZ85","t":"A345"},"00856":{"r":"4KAZ86","t":"A345"},"00858":{"r":"4KAZ88","t":"GALX"},"00864":{"r":"4KAZ100","t":"IL76"},"00865":{"r":"4KAZ101","t":"IL76"},"008D0":{"r":"4K-AZ208","t":"G280"},"00918":{"r":"4K-AZ280","t":"G280"},"00B20":{"r":"4KSW800","t":"B744"},"00B21":{"r":"4KSW888","t":"B744"},"00B70":{"r":"4K-SW880","t":"B763"},"00B78":{"r":"4KAZ888","t":"GLF4"},"00BB9":{"r":"4K-SW808","t":"B763"},"00BBE":{"r":"4KSW008","t":"B744"},"00BBF":{"r":"4KAZ11","t":"B752"},"00BC0":{"r":"4KAI08","t":"A346"},"00BC4":{"r":"4KAI88","t":"GLF6"},"00BC6":{"r":"4K-LAR","t":"GLF4"},"00BC7":{"r":"4KJJ888","t":"GLF5"},"00BE8":{"r":"4KAI01","t":"B763"},"00BE9":{"r":"4KAI001","t":"B77L"},"01097":{"r":"EX-37008"},"010F2":{"r":"EX-32001","t":"A320"},"010F4":{"r":"EX-37001","t":"B733"},"010F9":{"r":"EX-73401","t":"B734"},"01839":{"r":"EZ-A779","t":"B77L"},"0183A":{"r":"EZ-A778","t":"B77L"},"0183B":{"r":"EZ-A017","t":"B738"},"0183C":{"r":"EZ-A016","t":"B738"},"0183D":{"r":"EZ-A015","t":"B738"},"01842":{"r":"EZ-A010","t":"B752"},"01846":{"r":"EZ-A011","t":"B752"},"01847":{"r":"EZ-A012","t":"B752"},"01849":{"r":"EZ-A014","t":"B752"},"01854":{"r":"EZ-A106","t":"B712"},"01855":{"r":"EZ-A107","t":"B712"},"01858":{"r":"EZ-A004","t":"B738"},"01859":{"r":"EZ-A005","t":"B738"},"0185A":{"r":"EZ-A007","t":"B737"},"0185E":{"r":"EZ-A006","t":"B737"},"0185F":{"r":"EZ-A008","t":"B737"},"01860":{"r":"EZ-A009","t":"B737"},"01861":{"r":"EZ-A777","t":"B772"},"80001":{"r":"A5-RGF","t":"A319"},"80002":{"r":"A5-RGG","t":"A319"},"82209":{"r":"JU-1011","t":"B763"},"8220A":{"r":"JU-1012","t":"B763"},"83037":{"r":"UP-B5701","t":"B752"},"83065":{"r":"UP-Y4204","t":"YK42"},"83088":{"r":"UP-I7620","t":"IL76"},"830A5":{"r":"UP-A2001","t":"A320"},"830BD":{"r":"UP-CS302","t":"C25B"},"830C2":{"r":"UP-K3501","t":"B350"},"830ED":{"r":"UP-A3001","t":"A332"},"830FE":{"r":"UP-K3502","t":"B350"},"831E8":{"r":"UP-T5409","t":"T154"}}
|
||||
{"00005":{"r":"EK-73792","t":"B738"},"00007":{"r":"EK-32011","t":"A319"},"0000C":{"r":"EK32008","t":"A320"},"00010":{"r":"EK-73736","t":"B735"},"00013":{"r":"EK-11001","t":"AN12"},"00024":{"r":"EK-73705","t":"B738"},"0002F":{"r":"EK-12104","t":"AN12"},"0003C":{"r":"EK-RA01","t":"A319"},"0004A":{"r":"EK-32007","t":"A319"},"00059":{"r":"EK-95015","t":"SU95"},"0005A":{"r":"EK-95016","t":"SU95"},"0005F":{"r":"EW-412TH","t":"IL76"},"00076":{"r":"EK-74723","t":"B742"},"00079":{"r":"EK-74798","t":"B742"},"00087":{"r":"EK-74799","t":"B742"},"0009D":{"r":"EK-73775","t":"B735"},"0009F":{"r":"EK-73772","t":"B735"},"000A2":{"r":"EK-SHA","t":"B735"},"00801":{"r":"4K8888","t":"A319"},"00803":{"r":"4KAZ03","t":"A319"},"00804":{"r":"4KAZ04","t":"A319"},"00805":{"r":"4KAZ05","t":"A319"},"00806":{"r":"4KAI06","t":"GLF5"},"00807":{"r":"4KAI07","t":"A320"},"00808":{"r":"4KJJ8","t":"G280"},"0080C":{"r":"4KAZ12","t":"B752"},"00826":{"r":"4K-AZ38","t":"B752"},"00828":{"r":"4KAZ40","t":"IL76"},"00829":{"r":"4KAZ41","t":"IL76"},"0082B":{"r":"4K-AZ43","t":"B752"},"00836":{"r":"4K-AZ54","t":"A320"},"00838":{"r":"4K-AZ56","t":"AN12"},"0083C":{"r":"4KAZ60","t":"IL76"},"00840":{"r":"4KAZ64","t":"E190"},"00841":{"r":"4KAZ65","t":"E190"},"00842":{"r":"4KAZ66","t":"E190"},"00843":{"r":"4KAZ67","t":"E190"},"0084D":{"r":"4KAZ77","t":"A320"},"0084E":{"r":"4KAZ78","t":"A320"},"0084F":{"r":"4KAZ79","t":"A320"},"00850":{"r":"4KAZ80","t":"A320"},"00851":{"r":"4KAZ81","t":"B763"},"00852":{"r":"4KAZ82","t":"B763"},"00853":{"r":"4KAZ83","t":"A320"},"00854":{"r":"4KAZ84","t":"A320"},"00855":{"r":"4KAZ85","t":"A345"},"00856":{"r":"4KAZ86","t":"A345"},"00858":{"r":"4K-AZ88","t":"GALX"},"00864":{"r":"4KAZ100","t":"IL76"},"00865":{"r":"4KAZ101","t":"IL76"},"008D0":{"r":"4K-AZ208","t":"G280"},"00918":{"r":"4K-AZ280","t":"G280"},"00B20":{"r":"4KSW800","t":"B744"},"00B21":{"r":"4KSW888","t":"B744"},"00B70":{"r":"4K-SW880","t":"B763"},"00B78":{"r":"4KAZ888","t":"GLF4"},"00BB9":{"r":"4K-SW808","t":"B763"},"00BBE":{"r":"4KSW008","t":"B744"},"00BBF":{"r":"4KAZ11","t":"B752"},"00BC0":{"r":"4KAI08","t":"A346"},"00BC4":{"r":"4KAI88","t":"GLF6"},"00BC6":{"r":"4K-LAR","t":"GLF4"},"00BC7":{"r":"4KJJ888","t":"GLF5"},"00BC8":{"r":"4K-ASG","t":"GLF6"},"00BE8":{"r":"4KAI01","t":"B763"},"00BE9":{"r":"4KAI001","t":"B77L"},"01097":{"r":"EX-37008"},"010F2":{"r":"EX-32001","t":"A320"},"010F4":{"r":"EX-37001","t":"B733"},"010F9":{"r":"EX-73401","t":"B734"},"01839":{"r":"EZ-A779","t":"B77L"},"0183A":{"r":"EZ-A778","t":"B77L"},"0183B":{"r":"EZ-A017","t":"B738"},"0183C":{"r":"EZ-A016","t":"B738"},"0183D":{"r":"EZ-A015","t":"B738"},"01842":{"r":"EZ-A010","t":"B752"},"01846":{"r":"EZ-A011","t":"B752"},"01847":{"r":"EZ-A012","t":"B752"},"01849":{"r":"EZ-A014","t":"B752"},"01854":{"r":"EZ-A106","t":"B712"},"01855":{"r":"EZ-A107","t":"B712"},"01858":{"r":"EZ-A004","t":"B738"},"01859":{"r":"EZ-A005","t":"B738"},"0185A":{"r":"EZ-A007","t":"B737"},"0185E":{"r":"EZ-A006","t":"B737"},"0185F":{"r":"EZ-A008","t":"B737"},"01860":{"r":"EZ-A009","t":"B737"},"01861":{"r":"EZ-A777","t":"B772"},"80001":{"r":"A5-RGF","t":"A319"},"80002":{"r":"A5-RGG","t":"A319"},"82209":{"r":"JU-1011","t":"B763"},"8220A":{"r":"JU-1012","t":"B763"},"83037":{"r":"UP-B5701","t":"B752"},"83065":{"r":"UP-Y4204","t":"YK42"},"83088":{"r":"UP-I7620","t":"IL76"},"830A5":{"r":"UP-A2001","t":"A320"},"830BD":{"r":"UP-CS302","t":"C25B"},"830C2":{"r":"UP-K3501","t":"B350"},"830ED":{"r":"UP-A3001","t":"A332"},"830FE":{"r":"UP-K3502","t":"B350"},"831E8":{"r":"UP-T5409","t":"T154"}}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue