mirror of
https://github.com/eried/portapack-mayhem.git
synced 2025-01-23 21:21:29 -05:00
Merge pull request #422 from heurist1/adsb-improve-decode-and-gui
Adsb improve decode and gui
This commit is contained in:
commit
e985efd78b
1
.gitignore
vendored
1
.gitignore
vendored
@ -64,3 +64,4 @@ CMakeFiles/
|
|||||||
# Host OS leftovers
|
# Host OS leftovers
|
||||||
.DS_Store
|
.DS_Store
|
||||||
/firmware/CMakeCache.txt
|
/firmware/CMakeCache.txt
|
||||||
|
*.bak
|
||||||
|
444
firmware/application/apps/dump1090.hpp
Normal file
444
firmware/application/apps/dump1090.hpp
Normal file
@ -0,0 +1,444 @@
|
|||||||
|
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
|
||||||
|
//
|
||||||
|
// dump1090.h: main program header
|
||||||
|
//
|
||||||
|
// Copyright (c) 2014-2016 Oliver Jowett <oliver@mutability.co.uk>
|
||||||
|
//
|
||||||
|
// 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/>.
|
||||||
|
|
||||||
|
// This file incorporates work covered by the following copyright and
|
||||||
|
// permission notice:
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012 by Salvatore Sanfilippo <antirez@gmail.com>
|
||||||
|
//
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer in the
|
||||||
|
// documentation and/or other materials provided with the distribution.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#ifndef __DUMP1090_H
|
||||||
|
#define __DUMP1090_H
|
||||||
|
|
||||||
|
// Default version number, if not overriden by the Makefile
|
||||||
|
#ifndef MODES_DUMP1090_VERSION
|
||||||
|
# define MODES_DUMP1090_VERSION "unknown"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MODES_DUMP1090_VARIANT
|
||||||
|
# define MODES_DUMP1090_VARIANT "dump1090-unknown"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define MODES_DEFAULT_FREQ 1090000000
|
||||||
|
#define MODES_DEFAULT_WIDTH 1000
|
||||||
|
#define MODES_DEFAULT_HEIGHT 700
|
||||||
|
#define MODES_RTL_BUFFERS 15 // Number of RTL buffers
|
||||||
|
#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_MSG_SQUELCH_DB 4.0 // Minimum SNR, in dB
|
||||||
|
#define MODES_MSG_ENCODER_ERRS 3 // Maximum number of encoding errors
|
||||||
|
|
||||||
|
#define MODEAC_MSG_SAMPLES (25 * 2) // include up to the SPI bit
|
||||||
|
#define MODEAC_MSG_BYTES 2
|
||||||
|
#define MODEAC_MSG_SQUELCH_LEVEL 0x07FF // Average signal strength limit
|
||||||
|
|
||||||
|
#define MODES_PREAMBLE_US 8 // microseconds = bits
|
||||||
|
#define MODES_PREAMBLE_SAMPLES (MODES_PREAMBLE_US * 2)
|
||||||
|
#define MODES_PREAMBLE_SIZE (MODES_PREAMBLE_SAMPLES * sizeof(uint16_t))
|
||||||
|
#define MODES_LONG_MSG_BYTES 14
|
||||||
|
#define MODES_SHORT_MSG_BYTES 7
|
||||||
|
#define MODES_LONG_MSG_BITS (MODES_LONG_MSG_BYTES * 8)
|
||||||
|
#define MODES_SHORT_MSG_BITS (MODES_SHORT_MSG_BYTES * 8)
|
||||||
|
#define MODES_LONG_MSG_SAMPLES (MODES_LONG_MSG_BITS * 2)
|
||||||
|
#define MODES_SHORT_MSG_SAMPLES (MODES_SHORT_MSG_BITS * 2)
|
||||||
|
#define MODES_LONG_MSG_SIZE (MODES_LONG_MSG_SAMPLES * sizeof(uint16_t))
|
||||||
|
#define MODES_SHORT_MSG_SIZE (MODES_SHORT_MSG_SAMPLES * sizeof(uint16_t))
|
||||||
|
|
||||||
|
#define MODES_OS_PREAMBLE_SAMPLES (20)
|
||||||
|
#define MODES_OS_PREAMBLE_SIZE (MODES_OS_PREAMBLE_SAMPLES * sizeof(uint16_t))
|
||||||
|
#define MODES_OS_LONG_MSG_SAMPLES (268)
|
||||||
|
#define MODES_OS_SHORT_MSG_SAMPLES (135)
|
||||||
|
#define MODES_OS_LONG_MSG_SIZE (MODES_LONG_MSG_SAMPLES * sizeof(uint16_t))
|
||||||
|
#define MODES_OS_SHORT_MSG_SIZE (MODES_SHORT_MSG_SAMPLES * sizeof(uint16_t))
|
||||||
|
|
||||||
|
#define MODES_OUT_BUF_SIZE (1500)
|
||||||
|
#define MODES_OUT_FLUSH_SIZE (MODES_OUT_BUF_SIZE - 256)
|
||||||
|
#define MODES_OUT_FLUSH_INTERVAL (60000)
|
||||||
|
|
||||||
|
#define MODES_USER_LATLON_VALID (1<<0)
|
||||||
|
|
||||||
|
#define INVALID_ALTITUDE (-9999)
|
||||||
|
|
||||||
|
/* Where did a bit of data arrive from? In order of increasing priority */
|
||||||
|
typedef enum {
|
||||||
|
SOURCE_INVALID, /* data is not valid */
|
||||||
|
SOURCE_MODE_AC, /* A/C message */
|
||||||
|
SOURCE_MLAT, /* derived from mlat */
|
||||||
|
SOURCE_MODE_S, /* data from a Mode S message, no full CRC */
|
||||||
|
SOURCE_MODE_S_CHECKED, /* data from a Mode S message with full CRC */
|
||||||
|
SOURCE_TISB, /* data from a TIS-B extended squitter message */
|
||||||
|
SOURCE_ADSR, /* data from a ADS-R extended squitter message */
|
||||||
|
SOURCE_ADSB, /* data from a ADS-B extended squitter message */
|
||||||
|
} datasource_t;
|
||||||
|
|
||||||
|
/* What sort of address is this and who sent it?
|
||||||
|
* (Earlier values are higher priority)
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
ADDR_ADSB_ICAO, /* Mode S or ADS-B, ICAO address, transponder sourced */
|
||||||
|
ADDR_ADSB_ICAO_NT, /* ADS-B, ICAO address, non-transponder */
|
||||||
|
ADDR_ADSR_ICAO, /* ADS-R, ICAO address */
|
||||||
|
ADDR_TISB_ICAO, /* TIS-B, ICAO address */
|
||||||
|
|
||||||
|
ADDR_ADSB_OTHER, /* ADS-B, other address format */
|
||||||
|
ADDR_ADSR_OTHER, /* ADS-R, other address format */
|
||||||
|
ADDR_TISB_TRACKFILE, /* TIS-B, Mode A code + track file number */
|
||||||
|
ADDR_TISB_OTHER, /* TIS-B, other address format */
|
||||||
|
|
||||||
|
ADDR_MODE_A, /* Mode A */
|
||||||
|
|
||||||
|
ADDR_UNKNOWN /* unknown address format */
|
||||||
|
} addrtype_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
UNIT_FEET,
|
||||||
|
UNIT_METERS
|
||||||
|
} altitude_unit_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
UNIT_NAUTICAL_MILES,
|
||||||
|
UNIT_STATUTE_MILES,
|
||||||
|
UNIT_KILOMETERS,
|
||||||
|
} interactive_distance_unit_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ALTITUDE_BARO,
|
||||||
|
ALTITUDE_GEOM
|
||||||
|
} altitude_source_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
AG_INVALID,
|
||||||
|
AG_GROUND,
|
||||||
|
AG_AIRBORNE,
|
||||||
|
AG_UNCERTAIN
|
||||||
|
} airground_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SIL_INVALID, SIL_UNKNOWN, SIL_PER_SAMPLE, SIL_PER_HOUR
|
||||||
|
} sil_type_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
CPR_SURFACE, CPR_AIRBORNE, CPR_COARSE
|
||||||
|
} cpr_type_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
HEADING_INVALID, // Not set
|
||||||
|
HEADING_GROUND_TRACK, // Direction of track over ground, degrees clockwise from true north
|
||||||
|
HEADING_TRUE, // Heading, degrees clockwise from true north
|
||||||
|
HEADING_MAGNETIC, // Heading, degrees clockwise from magnetic north
|
||||||
|
HEADING_MAGNETIC_OR_TRUE, // HEADING_MAGNETIC or HEADING_TRUE depending on the HRD bit in opstatus
|
||||||
|
HEADING_TRACK_OR_HEADING // GROUND_TRACK / MAGNETIC / TRUE depending on the TAH bit in opstatus
|
||||||
|
} heading_type_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
COMMB_UNKNOWN,
|
||||||
|
COMMB_AMBIGUOUS,
|
||||||
|
COMMB_EMPTY_RESPONSE,
|
||||||
|
COMMB_DATALINK_CAPS,
|
||||||
|
COMMB_GICB_CAPS,
|
||||||
|
COMMB_AIRCRAFT_IDENT,
|
||||||
|
COMMB_ACAS_RA,
|
||||||
|
COMMB_VERTICAL_INTENT,
|
||||||
|
COMMB_TRACK_TURN,
|
||||||
|
COMMB_HEADING_SPEED
|
||||||
|
} commb_format_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NAV_MODE_AUTOPILOT = 1,
|
||||||
|
NAV_MODE_VNAV = 2,
|
||||||
|
NAV_MODE_ALT_HOLD = 4,
|
||||||
|
NAV_MODE_APPROACH = 8,
|
||||||
|
NAV_MODE_LNAV = 16,
|
||||||
|
NAV_MODE_TCAS = 32
|
||||||
|
} nav_modes_t;
|
||||||
|
|
||||||
|
// Matches encoding of the ES type 28/1 emergency/priority status subfield
|
||||||
|
typedef enum {
|
||||||
|
EMERGENCY_NONE = 0,
|
||||||
|
EMERGENCY_GENERAL = 1,
|
||||||
|
EMERGENCY_LIFEGUARD = 2,
|
||||||
|
EMERGENCY_MINFUEL = 3,
|
||||||
|
EMERGENCY_NORDO = 4,
|
||||||
|
EMERGENCY_UNLAWFUL = 5,
|
||||||
|
EMERGENCY_DOWNED = 6,
|
||||||
|
EMERGENCY_RESERVED = 7
|
||||||
|
} emergency_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NAV_ALT_INVALID, NAV_ALT_UNKNOWN, NAV_ALT_AIRCRAFT, NAV_ALT_MCP, NAV_ALT_FMS
|
||||||
|
} nav_altitude_source_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
|
||||||
|
#define MODES_INTERACTIVE_DISPLAY_TTL 60000 // Delete from display after 60 seconds
|
||||||
|
|
||||||
|
#define MODES_NET_HEARTBEAT_INTERVAL 60000 // milliseconds
|
||||||
|
|
||||||
|
#define MODES_CLIENT_BUF_SIZE 1024
|
||||||
|
#define MODES_NET_SNDBUF_SIZE (1024*64)
|
||||||
|
#define MODES_NET_SNDBUF_MAX (7)
|
||||||
|
|
||||||
|
#define HISTORY_SIZE 120
|
||||||
|
#define HISTORY_INTERVAL 30000
|
||||||
|
|
||||||
|
#define MODES_NOTUSED(V) ((void) V)
|
||||||
|
|
||||||
|
#define MAX_AMPLITUDE 65535.0
|
||||||
|
#define MAX_POWER (MAX_AMPLITUDE * MAX_AMPLITUDE)
|
||||||
|
|
||||||
|
#define FAUP_DEFAULT_RATE_MULTIPLIER 1.0 // FA Upload rate multiplier
|
||||||
|
|
||||||
|
|
||||||
|
//======================== structure declarations =========================
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SDR_NONE, SDR_IFILE, SDR_RTLSDR, SDR_BLADERF, SDR_HACKRF, SDR_LIMESDR
|
||||||
|
} sdr_type_t;
|
||||||
|
|
||||||
|
|
||||||
|
// The struct we use to store information about a decoded message.
|
||||||
|
struct modesMessage {
|
||||||
|
// Generic fields
|
||||||
|
unsigned char msg[MODES_LONG_MSG_BYTES]; // Binary message.
|
||||||
|
unsigned char verbatim[MODES_LONG_MSG_BYTES]; // Binary message, as originally received before correction
|
||||||
|
int msgbits; // Number of bits in message
|
||||||
|
int msgtype; // Downlink format #
|
||||||
|
uint32_t crc; // Message CRC
|
||||||
|
int correctedbits; // No. of bits corrected
|
||||||
|
uint32_t addr; // Address Announced
|
||||||
|
addrtype_t addrtype; // address format / source
|
||||||
|
uint64_t timestampMsg; // Timestamp of the message (12MHz clock)
|
||||||
|
uint64_t sysTimestampMsg; // Timestamp of the message (system time)
|
||||||
|
int remote; // If set this message is from a remote station
|
||||||
|
double signalLevel; // RSSI, in the range [0..1], as a fraction of full-scale power
|
||||||
|
int score; // Scoring from scoreModesMessage, if used
|
||||||
|
int reliable; // is this a "reliable" message (uncorrected DF11/DF17/DF18)?
|
||||||
|
|
||||||
|
datasource_t source; // Characterizes the overall message source
|
||||||
|
|
||||||
|
// Raw data, just extracted directly from the message
|
||||||
|
// The names reflect the field names in Annex 4
|
||||||
|
unsigned IID; // extracted from CRC of DF11s
|
||||||
|
unsigned AA;
|
||||||
|
unsigned AC;
|
||||||
|
unsigned CA;
|
||||||
|
unsigned CC;
|
||||||
|
unsigned CF;
|
||||||
|
unsigned DR;
|
||||||
|
unsigned FS;
|
||||||
|
unsigned ID;
|
||||||
|
unsigned KE;
|
||||||
|
unsigned ND;
|
||||||
|
unsigned RI;
|
||||||
|
unsigned SL;
|
||||||
|
unsigned UM;
|
||||||
|
unsigned VS;
|
||||||
|
unsigned char MB[7];
|
||||||
|
unsigned char MD[10];
|
||||||
|
unsigned char ME[7];
|
||||||
|
unsigned char MV[7];
|
||||||
|
|
||||||
|
// Decoded data
|
||||||
|
unsigned altitude_baro_valid : 1;
|
||||||
|
unsigned altitude_geom_valid : 1;
|
||||||
|
unsigned track_valid : 1;
|
||||||
|
unsigned track_rate_valid : 1;
|
||||||
|
unsigned heading_valid : 1;
|
||||||
|
unsigned roll_valid : 1;
|
||||||
|
unsigned gs_valid : 1;
|
||||||
|
unsigned ias_valid : 1;
|
||||||
|
unsigned tas_valid : 1;
|
||||||
|
unsigned mach_valid : 1;
|
||||||
|
unsigned baro_rate_valid : 1;
|
||||||
|
unsigned geom_rate_valid : 1;
|
||||||
|
unsigned squawk_valid : 1;
|
||||||
|
unsigned callsign_valid : 1;
|
||||||
|
unsigned cpr_valid : 1;
|
||||||
|
unsigned cpr_odd : 1;
|
||||||
|
unsigned cpr_decoded : 1;
|
||||||
|
unsigned cpr_relative : 1;
|
||||||
|
unsigned category_valid : 1;
|
||||||
|
unsigned geom_delta_valid : 1;
|
||||||
|
unsigned from_mlat : 1;
|
||||||
|
unsigned from_tisb : 1;
|
||||||
|
unsigned spi_valid : 1;
|
||||||
|
unsigned spi : 1;
|
||||||
|
unsigned alert_valid : 1;
|
||||||
|
unsigned alert : 1;
|
||||||
|
unsigned emergency_valid : 1;
|
||||||
|
|
||||||
|
unsigned metype; // DF17/18 ME type
|
||||||
|
unsigned mesub; // DF17/18 ME subtype
|
||||||
|
|
||||||
|
commb_format_t commb_format; // Inferred format of a comm-b message
|
||||||
|
|
||||||
|
// valid if altitude_baro_valid:
|
||||||
|
int altitude_baro; // Altitude in either feet or meters
|
||||||
|
altitude_unit_t altitude_baro_unit; // the unit used for altitude
|
||||||
|
|
||||||
|
// valid if altitude_geom_valid:
|
||||||
|
int altitude_geom; // Altitude in either feet or meters
|
||||||
|
altitude_unit_t altitude_geom_unit; // the unit used for altitude
|
||||||
|
|
||||||
|
// following fields are valid if the corresponding _valid field is set:
|
||||||
|
int geom_delta; // Difference between geometric and baro alt
|
||||||
|
float heading; // ground track or heading, degrees (0-359). Reported directly or computed from from EW and NS velocity
|
||||||
|
heading_type_t heading_type;// how to interpret 'track_or_heading'
|
||||||
|
float track_rate; // Rate of change of track, degrees/second
|
||||||
|
float roll; // Roll, degrees, negative is left roll
|
||||||
|
struct {
|
||||||
|
// Groundspeed, kts, reported directly or computed from from EW and NS velocity
|
||||||
|
// For surface movement, this has different interpretations for v0 and v2; both
|
||||||
|
// fields are populated. The tracking layer will update "gs.selected".
|
||||||
|
float v0;
|
||||||
|
float v2;
|
||||||
|
float selected;
|
||||||
|
} gs;
|
||||||
|
unsigned ias; // Indicated airspeed, kts
|
||||||
|
unsigned tas; // True airspeed, kts
|
||||||
|
double mach; // Mach number
|
||||||
|
int baro_rate; // Rate of change of barometric altitude, feet/minute
|
||||||
|
int geom_rate; // Rate of change of geometric (GNSS / INS) altitude, feet/minute
|
||||||
|
unsigned squawk; // 13 bits identity (Squawk), encoded as 4 hex digits
|
||||||
|
char callsign[9]; // 8 chars flight number, NUL-terminated
|
||||||
|
unsigned category; // A0 - D7 encoded as a single hex byte
|
||||||
|
emergency_t emergency; // emergency/priority status
|
||||||
|
|
||||||
|
// valid if cpr_valid
|
||||||
|
cpr_type_t cpr_type; // The encoding type used (surface, airborne, coarse TIS-B)
|
||||||
|
unsigned cpr_lat; // Non decoded latitude.
|
||||||
|
unsigned cpr_lon; // Non decoded longitude.
|
||||||
|
unsigned cpr_nucp; // NUCp/NIC value implied by message type
|
||||||
|
|
||||||
|
airground_t airground; // air/ground state
|
||||||
|
|
||||||
|
// valid if cpr_decoded:
|
||||||
|
double decoded_lat;
|
||||||
|
double decoded_lon;
|
||||||
|
unsigned decoded_nic;
|
||||||
|
unsigned decoded_rc;
|
||||||
|
|
||||||
|
// various integrity/accuracy things
|
||||||
|
struct {
|
||||||
|
unsigned nic_a_valid : 1;
|
||||||
|
unsigned nic_b_valid : 1;
|
||||||
|
unsigned nic_c_valid : 1;
|
||||||
|
unsigned nic_baro_valid : 1;
|
||||||
|
unsigned nac_p_valid : 1;
|
||||||
|
unsigned nac_v_valid : 1;
|
||||||
|
unsigned gva_valid : 1;
|
||||||
|
unsigned sda_valid : 1;
|
||||||
|
|
||||||
|
unsigned nic_a : 1; // if nic_a_valid
|
||||||
|
unsigned nic_b : 1; // if nic_b_valid
|
||||||
|
unsigned nic_c : 1; // if nic_c_valid
|
||||||
|
unsigned nic_baro : 1; // if nic_baro_valid
|
||||||
|
|
||||||
|
unsigned nac_p : 4; // if nac_p_valid
|
||||||
|
unsigned nac_v : 3; // if nac_v_valid
|
||||||
|
|
||||||
|
unsigned sil : 2; // if sil_type != SIL_INVALID
|
||||||
|
sil_type_t sil_type;
|
||||||
|
|
||||||
|
unsigned gva : 2; // if gva_valid
|
||||||
|
|
||||||
|
unsigned sda : 2; // if sda_valid
|
||||||
|
} accuracy;
|
||||||
|
|
||||||
|
// Operational Status
|
||||||
|
struct {
|
||||||
|
unsigned valid : 1;
|
||||||
|
unsigned version : 3;
|
||||||
|
|
||||||
|
unsigned om_acas_ra : 1;
|
||||||
|
unsigned om_ident : 1;
|
||||||
|
unsigned om_atc : 1;
|
||||||
|
unsigned om_saf : 1;
|
||||||
|
|
||||||
|
unsigned cc_acas : 1;
|
||||||
|
unsigned cc_cdti : 1;
|
||||||
|
unsigned cc_1090_in : 1;
|
||||||
|
unsigned cc_arv : 1;
|
||||||
|
unsigned cc_ts : 1;
|
||||||
|
unsigned cc_tc : 2;
|
||||||
|
unsigned cc_uat_in : 1;
|
||||||
|
unsigned cc_poa : 1;
|
||||||
|
unsigned cc_b2_low : 1;
|
||||||
|
unsigned cc_lw_valid : 1;
|
||||||
|
|
||||||
|
heading_type_t tah;
|
||||||
|
heading_type_t hrd;
|
||||||
|
|
||||||
|
unsigned cc_lw;
|
||||||
|
unsigned cc_antenna_offset;
|
||||||
|
} opstatus;
|
||||||
|
|
||||||
|
// combined:
|
||||||
|
// Target State & Status (ADS-B V2 only)
|
||||||
|
// Comm-B BDS4,0 Vertical Intent
|
||||||
|
struct {
|
||||||
|
unsigned heading_valid : 1;
|
||||||
|
unsigned fms_altitude_valid : 1;
|
||||||
|
unsigned mcp_altitude_valid : 1;
|
||||||
|
unsigned qnh_valid : 1;
|
||||||
|
unsigned modes_valid : 1;
|
||||||
|
|
||||||
|
float heading; // heading, degrees (0-359) (could be magnetic or true heading; magnetic recommended)
|
||||||
|
heading_type_t heading_type;
|
||||||
|
unsigned fms_altitude; // FMS selected altitude
|
||||||
|
unsigned mcp_altitude; // MCP/FCU selected altitude
|
||||||
|
float qnh; // altimeter setting (QFE or QNH/QNE), millibars
|
||||||
|
|
||||||
|
nav_altitude_source_t altitude_source;
|
||||||
|
|
||||||
|
nav_modes_t modes;
|
||||||
|
} nav;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // __DUMP1090_H
|
@ -49,7 +49,7 @@ void RecentEntriesTable<AircraftRecentEntries>::draw(
|
|||||||
if (entry_age < ADSB_DECAY_A) {
|
if (entry_age < ADSB_DECAY_A) {
|
||||||
aged_color = 0x10;
|
aged_color = 0x10;
|
||||||
target_color = Color::green();
|
target_color = Color::green();
|
||||||
} else if ((entry_age >= ADSB_DECAY_A) && (entry_age < ADSB_DECAY_B)) {
|
} else if (entry_age < ADSB_DECAY_B) {
|
||||||
aged_color = 0x07;
|
aged_color = 0x07;
|
||||||
target_color = Color::light_grey();
|
target_color = Color::light_grey();
|
||||||
} else {
|
} else {
|
||||||
@ -59,10 +59,21 @@ void RecentEntriesTable<AircraftRecentEntries>::draw(
|
|||||||
|
|
||||||
std::string entry_string = "\x1B";
|
std::string entry_string = "\x1B";
|
||||||
entry_string += aged_color;
|
entry_string += aged_color;
|
||||||
|
#if false
|
||||||
entry_string += to_string_hex(entry.ICAO_address, 6) + " " +
|
entry_string += to_string_hex(entry.ICAO_address, 6) + " " +
|
||||||
entry.callsign + " " +
|
entry.callsign + " " +
|
||||||
(entry.hits <= 999 ? to_string_dec_uint(entry.hits, 4) : "999+") + " " +
|
(entry.hits <= 999 ? to_string_dec_uint(entry.hits, 4) : "999+") + " " +
|
||||||
entry.time_string;
|
entry.time_string;
|
||||||
|
#else
|
||||||
|
// SBT
|
||||||
|
entry_string +=
|
||||||
|
(entry.callsign[0]!=' ' ? entry.callsign + " " : to_string_hex(entry.ICAO_address, 6) + " ") +
|
||||||
|
to_string_dec_uint((unsigned int)((entry.pos.altitude+50)/100),4) +
|
||||||
|
to_string_dec_uint((unsigned int)entry.velo.speed,4) +
|
||||||
|
to_string_dec_uint((unsigned int)(entry.amp>>9),4) + " " +
|
||||||
|
(entry.hits <= 999 ? to_string_dec_uint(entry.hits, 3) + " " : "1k+ ") +
|
||||||
|
to_string_dec_uint(entry.age, 3);
|
||||||
|
#endif
|
||||||
|
|
||||||
painter.draw_string(
|
painter.draw_string(
|
||||||
target_rect.location(),
|
target_rect.location(),
|
||||||
@ -71,7 +82,7 @@ void RecentEntriesTable<AircraftRecentEntries>::draw(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (entry.pos.valid)
|
if (entry.pos.valid)
|
||||||
painter.draw_bitmap(target_rect.location() + Point(15 * 8, 0), bitmap_target, target_color, style.background);
|
painter.draw_bitmap(target_rect.location() + Point(8 * 8, 0), bitmap_target, target_color, style.background);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ADSBLogger::log_str(std::string& logline) {
|
void ADSBLogger::log_str(std::string& logline) {
|
||||||
@ -173,6 +184,7 @@ ADSBRxDetailsView::ADSBRxDetailsView(
|
|||||||
text_callsign.set(entry_copy.callsign);
|
text_callsign.set(entry_copy.callsign);
|
||||||
|
|
||||||
button_see_map.on_select = [this, &nav](Button&) {
|
button_see_map.on_select = [this, &nav](Button&) {
|
||||||
|
if (!send_updates) { // Prevent recursivley launching the map
|
||||||
geomap_view = nav.push<GeoMapView>(
|
geomap_view = nav.push<GeoMapView>(
|
||||||
entry_copy.callsign,
|
entry_copy.callsign,
|
||||||
entry_copy.pos.altitude,
|
entry_copy.pos.altitude,
|
||||||
@ -184,6 +196,7 @@ ADSBRxDetailsView::ADSBRxDetailsView(
|
|||||||
send_updates = false;
|
send_updates = false;
|
||||||
});
|
});
|
||||||
send_updates = true;
|
send_updates = true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -192,11 +205,41 @@ void ADSBRxView::focus() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ADSBRxView::~ADSBRxView() {
|
ADSBRxView::~ADSBRxView() {
|
||||||
|
receiver_model.set_tuning_frequency(prevFreq);
|
||||||
|
|
||||||
rtc_time::signal_tick_second -= signal_token_tick_second;
|
rtc_time::signal_tick_second -= signal_token_tick_second;
|
||||||
receiver_model.disable();
|
receiver_model.disable();
|
||||||
baseband::shutdown();
|
baseband::shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AircraftRecentEntry ADSBRxView::find_or_create_entry(uint32_t ICAO_address) {
|
||||||
|
auto it = find(recent, ICAO_address);
|
||||||
|
|
||||||
|
// If not found
|
||||||
|
if (it == std::end(recent)){
|
||||||
|
recent.emplace_front(ICAO_address); // Add it
|
||||||
|
truncate_entries(recent); // Truncate the list
|
||||||
|
sort_entries_by_state();
|
||||||
|
it = find(recent, ICAO_address); // Find it again
|
||||||
|
}
|
||||||
|
return *it;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ADSBRxView::replace_entry(AircraftRecentEntry & entry)
|
||||||
|
{
|
||||||
|
uint32_t ICAO_address = entry.ICAO_address;
|
||||||
|
|
||||||
|
std::replace_if( recent.begin(), recent.end(),
|
||||||
|
[ICAO_address](const AircraftRecentEntry & compEntry) {return ICAO_address == compEntry.ICAO_address;},
|
||||||
|
entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ADSBRxView::sort_entries_by_state()
|
||||||
|
{
|
||||||
|
// Sorting List pn age_state using lambda function as comparator
|
||||||
|
recent.sort([](const AircraftRecentEntry & left, const AircraftRecentEntry & right){return (left.age_state < right.age_state); });
|
||||||
|
}
|
||||||
|
|
||||||
void ADSBRxView::on_frame(const ADSBFrameMessage * message) {
|
void ADSBRxView::on_frame(const ADSBFrameMessage * message) {
|
||||||
rtc::RTC datetime;
|
rtc::RTC datetime;
|
||||||
std::string str_timestamp;
|
std::string str_timestamp;
|
||||||
@ -209,9 +252,15 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) {
|
|||||||
|
|
||||||
if (frame.check_CRC() && ICAO_address) {
|
if (frame.check_CRC() && ICAO_address) {
|
||||||
rtcGetTime(&RTCD1, &datetime);
|
rtcGetTime(&RTCD1, &datetime);
|
||||||
auto& entry = ::on_packet(recent, ICAO_address);
|
auto entry = find_or_create_entry(ICAO_address);
|
||||||
frame.set_rx_timestamp(datetime.minute() * 60 + datetime.second());
|
frame.set_rx_timestamp(datetime.minute() * 60 + datetime.second());
|
||||||
entry.reset_age();
|
entry.reset_age();
|
||||||
|
if (entry.hits==0)
|
||||||
|
{
|
||||||
|
entry.amp = message->amp;
|
||||||
|
} else {
|
||||||
|
entry.amp = ((entry.amp*15)+message->amp)>>4;
|
||||||
|
}
|
||||||
str_timestamp = to_string_datetime(datetime, HMS);
|
str_timestamp = to_string_datetime(datetime, HMS);
|
||||||
entry.set_time_string(str_timestamp);
|
entry.set_time_string(str_timestamp);
|
||||||
|
|
||||||
@ -224,12 +273,16 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) {
|
|||||||
uint8_t msg_sub = frame.get_msg_sub();
|
uint8_t msg_sub = frame.get_msg_sub();
|
||||||
uint8_t * raw_data = frame.get_raw_data();
|
uint8_t * raw_data = frame.get_raw_data();
|
||||||
|
|
||||||
|
// 4: // surveillance, altitude reply
|
||||||
if ((msg_type >= AIRCRAFT_ID_L) && (msg_type <= AIRCRAFT_ID_H)) {
|
if ((msg_type >= AIRCRAFT_ID_L) && (msg_type <= AIRCRAFT_ID_H)) {
|
||||||
callsign = decode_frame_id(frame);
|
callsign = decode_frame_id(frame);
|
||||||
entry.set_callsign(callsign);
|
entry.set_callsign(callsign);
|
||||||
logentry+=callsign+" ";
|
logentry+=callsign+" ";
|
||||||
}
|
}
|
||||||
//
|
// 9:
|
||||||
|
// 18: { // Extended squitter/non-transponder
|
||||||
|
// 21: // Comm-B, identity reply
|
||||||
|
// 20: // Comm-B, altitude reply
|
||||||
else if (((msg_type >= AIRBORNE_POS_BARO_L) && (msg_type <= AIRBORNE_POS_BARO_H)) ||
|
else if (((msg_type >= AIRBORNE_POS_BARO_L) && (msg_type <= AIRBORNE_POS_BARO_H)) ||
|
||||||
((msg_type >= AIRBORNE_POS_GPS_L) && (msg_type <= AIRBORNE_POS_GPS_H))) {
|
((msg_type >= AIRBORNE_POS_GPS_L) && (msg_type <= AIRBORNE_POS_GPS_H))) {
|
||||||
entry.set_frame_pos(frame, raw_data[6] & 4);
|
entry.set_frame_pos(frame, raw_data[6] & 4);
|
||||||
@ -250,12 +303,6 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) {
|
|||||||
entry.set_info_string(str_info);
|
entry.set_info_string(str_info);
|
||||||
logentry+=log_info + " ";
|
logentry+=log_info + " ";
|
||||||
|
|
||||||
// we only want to update the details view if the frame
|
|
||||||
// we received has the same ICAO address, i.e. belongs to
|
|
||||||
// the same aircraft:
|
|
||||||
if(send_updates && details_view->get_current_entry().ICAO_address == ICAO_address) {
|
|
||||||
details_view->update(entry);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if(msg_type == AIRBORNE_VEL && msg_sub >= VEL_GND_SUBSONIC && msg_sub <= VEL_AIR_SUPERSONIC){
|
} else if(msg_type == AIRBORNE_VEL && msg_sub >= VEL_GND_SUBSONIC && msg_sub <= VEL_AIR_SUPERSONIC){
|
||||||
entry.set_frame_velo(frame);
|
entry.set_frame_velo(frame);
|
||||||
@ -263,13 +310,10 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) {
|
|||||||
" Hdg:" + to_string_dec_uint(entry.velo.heading) +
|
" Hdg:" + to_string_dec_uint(entry.velo.heading) +
|
||||||
" Spd: "+ to_string_dec_int(entry.velo.speed);
|
" Spd: "+ to_string_dec_int(entry.velo.speed);
|
||||||
|
|
||||||
// same here:
|
|
||||||
if (send_updates && details_view->get_current_entry().ICAO_address == ICAO_address) {
|
|
||||||
details_view->update(entry);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
recent_entries_view.set_dirty();
|
replace_entry(entry);
|
||||||
|
|
||||||
logger = std::make_unique<ADSBLogger>();
|
logger = std::make_unique<ADSBLogger>();
|
||||||
if (logger) {
|
if (logger) {
|
||||||
@ -287,13 +331,16 @@ void ADSBRxView::on_tick_second() {
|
|||||||
entry.inc_age();
|
entry.inc_age();
|
||||||
|
|
||||||
if (details_view) {
|
if (details_view) {
|
||||||
if (send_updates && (entry.key() == detailed_entry_key))
|
if (send_updates && (entry.key() == detailed_entry_key)) // Check if the ICAO address match
|
||||||
details_view->update(entry);
|
details_view->update(entry);
|
||||||
} else {
|
|
||||||
if ((entry.age == ADSB_DECAY_A) || (entry.age == ADSB_DECAY_B))
|
|
||||||
recent_entries_view.set_dirty();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sort the list if it is being displayed
|
||||||
|
if (!send_updates) {
|
||||||
|
sort_entries_by_state();
|
||||||
|
recent_entries_view.set_dirty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ADSBRxView::ADSBRxView(NavigationView& nav) {
|
ADSBRxView::ADSBRxView(NavigationView& nav) {
|
||||||
@ -322,6 +369,8 @@ ADSBRxView::ADSBRxView(NavigationView& nav) {
|
|||||||
on_tick_second();
|
on_tick_second();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
prevFreq = receiver_model.tuning_frequency();
|
||||||
|
|
||||||
baseband::set_adsb();
|
baseband::set_adsb();
|
||||||
|
|
||||||
receiver_model.set_tuning_frequency(1090000000);
|
receiver_model.set_tuning_frequency(1090000000);
|
||||||
|
@ -32,6 +32,8 @@
|
|||||||
#include "adsb.hpp"
|
#include "adsb.hpp"
|
||||||
#include "message.hpp"
|
#include "message.hpp"
|
||||||
|
|
||||||
|
#include "crc.hpp"
|
||||||
|
|
||||||
using namespace adsb;
|
using namespace adsb;
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
@ -71,7 +73,10 @@ struct AircraftRecentEntry {
|
|||||||
|
|
||||||
uint32_t ICAO_address { };
|
uint32_t ICAO_address { };
|
||||||
uint16_t hits { 0 };
|
uint16_t hits { 0 };
|
||||||
|
|
||||||
|
uint16_t age_state { 1 };
|
||||||
uint32_t age { 0 };
|
uint32_t age { 0 };
|
||||||
|
uint32_t amp { 0 };
|
||||||
adsb_pos pos { false, 0, 0, 0 };
|
adsb_pos pos { false, 0, 0, 0 };
|
||||||
adsb_vel velo { false, 0, 999, 0 };
|
adsb_vel velo { false, 0, 999, 0 };
|
||||||
ADSBFrame frame_pos_even { };
|
ADSBFrame frame_pos_even { };
|
||||||
@ -129,6 +134,14 @@ struct AircraftRecentEntry {
|
|||||||
|
|
||||||
void inc_age() {
|
void inc_age() {
|
||||||
age++;
|
age++;
|
||||||
|
if (age < ADSB_DECAY_A)
|
||||||
|
{
|
||||||
|
age_state = pos.valid ? 0 : 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
age_state = (age < ADSB_DECAY_B) ? 2 : 3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -239,16 +252,30 @@ public:
|
|||||||
|
|
||||||
std::string title() const override { return "ADS-B receive"; };
|
std::string title() const override { return "ADS-B receive"; };
|
||||||
|
|
||||||
|
void replace_entry(AircraftRecentEntry & entry);
|
||||||
|
AircraftRecentEntry find_or_create_entry(uint32_t ICAO_address);
|
||||||
|
void sort_entries_by_state();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
rf::Frequency prevFreq;
|
||||||
std::unique_ptr<ADSBLogger> logger { };
|
std::unique_ptr<ADSBLogger> logger { };
|
||||||
void on_frame(const ADSBFrameMessage * message);
|
void on_frame(const ADSBFrameMessage * message);
|
||||||
void on_tick_second();
|
void on_tick_second();
|
||||||
|
|
||||||
const RecentEntriesColumns columns { {
|
const RecentEntriesColumns columns { {
|
||||||
|
#if false
|
||||||
{ "ICAO", 6 },
|
{ "ICAO", 6 },
|
||||||
{ "Callsign", 9 },
|
{ "Callsign", 9 },
|
||||||
{ "Hits", 4 },
|
{ "Hits", 4 },
|
||||||
{ "Time", 8 }
|
{ "Time", 8 }
|
||||||
|
#else
|
||||||
|
{ "ICAO/Call", 9 },
|
||||||
|
{ "Lvl", 3 },
|
||||||
|
{ "Spd", 3 },
|
||||||
|
{ "Amp", 3 },
|
||||||
|
{ "Hit", 3 },
|
||||||
|
{ "Age", 3 }
|
||||||
|
#endif
|
||||||
} };
|
} };
|
||||||
AircraftRecentEntries recent { };
|
AircraftRecentEntries recent { };
|
||||||
RecentEntriesView<RecentEntries<AircraftRecentEntry>> recent_entries_view { columns, recent };
|
RecentEntriesView<RecentEntries<AircraftRecentEntry>> recent_entries_view { columns, recent };
|
||||||
|
@ -32,11 +32,9 @@ using namespace adsb;
|
|||||||
|
|
||||||
void ADSBRXProcessor::execute(const buffer_c8_t& buffer) {
|
void ADSBRXProcessor::execute(const buffer_c8_t& buffer) {
|
||||||
int8_t re, im;
|
int8_t re, im;
|
||||||
float mag;
|
uint32_t mag;
|
||||||
uint32_t c;
|
uint32_t c;
|
||||||
uint8_t level, bit, byte { };
|
uint8_t bit, byte{};
|
||||||
//bool confidence;
|
|
||||||
bool first_in_window, last_in_window;
|
|
||||||
|
|
||||||
// This is called at 2M/2048 = 977Hz
|
// This is called at 2M/2048 = 977Hz
|
||||||
// One pulse = 500ns = 2 samples
|
// One pulse = 500ns = 2 samples
|
||||||
@ -47,100 +45,112 @@ void ADSBRXProcessor::execute(const buffer_c8_t& buffer) {
|
|||||||
for (size_t i = 0; i < buffer.count; i++) {
|
for (size_t i = 0; i < buffer.count; i++) {
|
||||||
|
|
||||||
// Compute sample's magnitude
|
// Compute sample's magnitude
|
||||||
re = buffer.p[i].real();
|
re = (int32_t)buffer.p[i].real(); // make re float and scale it
|
||||||
im = buffer.p[i].imag();
|
im = (int32_t)buffer.p[i].imag(); // make re float and scale it
|
||||||
mag = __builtin_sqrtf((re * re) + (im * im)) * k;
|
mag = ((uint32_t)(re*re) + (uint32_t)(im*im));
|
||||||
|
|
||||||
// Only used for preamble detection and visualisation
|
|
||||||
level = (mag < 0.3) ? 0 : // Blank weak signals
|
|
||||||
(mag > prev_mag) ? 1 : 0;
|
|
||||||
|
|
||||||
if (decoding) {
|
if (decoding) {
|
||||||
// Decode
|
// Decode
|
||||||
|
|
||||||
// 1 bit lasts 2 samples
|
// 1 bit lasts 2 samples
|
||||||
if (sample_count & 1) {
|
if (sample_count & 1) {
|
||||||
if ((prev_mag < threshold_low) && (mag < threshold_low)) {
|
if (bit_count >= msgLen)
|
||||||
// Both under window, silence.
|
{
|
||||||
if (null_count > 3) {
|
const ADSBFrameMessage message(frame, amp);
|
||||||
const ADSBFrameMessage message(frame);
|
|
||||||
shared_memory.application_queue.push(message);
|
shared_memory.application_queue.push(message);
|
||||||
|
|
||||||
decoding = false;
|
decoding = false;
|
||||||
} else
|
bit = (prev_mag > mag) ? 1 : 0;
|
||||||
null_count++;
|
|
||||||
|
|
||||||
//confidence = false;
|
|
||||||
if (prev_mag > mag)
|
|
||||||
bit = 1;
|
|
||||||
else
|
|
||||||
bit = 0;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
null_count = 0;
|
|
||||||
|
|
||||||
first_in_window = ((prev_mag >= threshold_low) && (prev_mag <= threshold_high));
|
|
||||||
last_in_window = ((mag >= threshold_low) && (mag <= threshold_high));
|
|
||||||
|
|
||||||
if ((first_in_window && !last_in_window) || (!first_in_window && last_in_window)) {
|
|
||||||
//confidence = true;
|
|
||||||
if (prev_mag > mag)
|
|
||||||
bit = 1;
|
|
||||||
else
|
|
||||||
bit = 0;
|
|
||||||
} else {
|
|
||||||
//confidence = false;
|
|
||||||
if (prev_mag > mag)
|
|
||||||
bit = 1;
|
|
||||||
else
|
|
||||||
bit = 0;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//confidence = true;
|
||||||
|
bit = (prev_mag > mag) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte = bit | (byte << 1);
|
byte = bit | (byte << 1);
|
||||||
bit_count++;
|
bit_count++;
|
||||||
|
|
||||||
|
// Perform checks at the end of the first byte
|
||||||
if (!(bit_count & 7)) {
|
if (!(bit_count & 7)) {
|
||||||
// Got one byte
|
|
||||||
|
// Store the byte
|
||||||
frame.push_byte(byte);
|
frame.push_byte(byte);
|
||||||
|
|
||||||
|
// Check at the end of the first byte of the message
|
||||||
|
uint8_t df = (byte >> 3);
|
||||||
|
if ( (bit_count == 8) && !(df & 0x10) ) {
|
||||||
|
msgLen = 56; // DFs 16 or greater are long 112. DFs 15 or less are short 56.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Abondon all frames that arent DF17 or DF18 extended squitters
|
||||||
|
if ( (bit_count == 8) && !((df == 17)||(df == 18)) ) {
|
||||||
|
decoding = false;
|
||||||
|
bit = (prev_mag > mag) ? 1 : 0;
|
||||||
|
frame.clear();
|
||||||
}
|
}
|
||||||
|
} // last bit of a byte
|
||||||
|
} // Second sample of each bit
|
||||||
sample_count++;
|
sample_count++;
|
||||||
} else {
|
|
||||||
// Look for preamble
|
|
||||||
|
|
||||||
// Shift
|
|
||||||
for (c = 0; c < (ADSB_PREAMBLE_LENGTH - 1); c++)
|
|
||||||
shifter[c] = shifter[c + 1];
|
|
||||||
shifter[15] = std::make_pair(mag, level);
|
|
||||||
|
|
||||||
// Compare
|
|
||||||
for (c = 0; c < ADSB_PREAMBLE_LENGTH; c++) {
|
|
||||||
if (shifter[c].second != adsb_preamble[c])
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c == ADSB_PREAMBLE_LENGTH) {
|
// Continue looking for preamble even if in a packet
|
||||||
|
// switch is new preamble id higher magnitude
|
||||||
|
|
||||||
|
// Shift the preamble
|
||||||
|
for (c = 0; c < (ADSB_PREAMBLE_LENGTH ); c++) { shifter[c] = shifter[c + 1]; }
|
||||||
|
shifter[ADSB_PREAMBLE_LENGTH] = mag;
|
||||||
|
|
||||||
|
// First check of relations between the first 10 samples
|
||||||
|
// representing a valid preamble. We don't even investigate further
|
||||||
|
// if this simple test is not passed
|
||||||
|
if (shifter[0] < shifter[1] &&
|
||||||
|
shifter[1] > shifter[2] &&
|
||||||
|
shifter[2] < shifter[3] &&
|
||||||
|
shifter[3] > shifter[4] &&
|
||||||
|
shifter[4] < shifter[1] &&
|
||||||
|
shifter[5] < shifter[1] &&
|
||||||
|
shifter[6] < shifter[1] &&
|
||||||
|
shifter[7] < shifter[1] &&
|
||||||
|
shifter[8] > shifter[9] &&
|
||||||
|
shifter[9] < shifter[10] &&
|
||||||
|
shifter[10]> shifter[11] )
|
||||||
|
{
|
||||||
|
// The samples between the two spikes must be < than the average
|
||||||
|
// of the high spikes level. We don't test bits too near to
|
||||||
|
// the high levels as signals can be out of phase so part of the
|
||||||
|
// energy can be in the near samples
|
||||||
|
int32_t thisAmp = (shifter[1] + shifter[3] + shifter[8] + shifter[10]);
|
||||||
|
int32_t high = thisAmp / 9;
|
||||||
|
if (
|
||||||
|
shifter[5] < high &&
|
||||||
|
shifter[6] < high &&
|
||||||
|
// Similarly samples in the range 11-13 must be low, as it is the
|
||||||
|
// space between the preamble and real data. Again we don't test
|
||||||
|
// bits too near to high levels, see above
|
||||||
|
shifter[12] < high &&
|
||||||
|
shifter[13] < high &&
|
||||||
|
shifter[14] < high )
|
||||||
|
{
|
||||||
|
if ((decoding == false) || // New preamble
|
||||||
|
((decoding == true) && (thisAmp > amp))) // Higher power than existing packet
|
||||||
|
{
|
||||||
decoding = true;
|
decoding = true;
|
||||||
|
msgLen = 112;
|
||||||
|
amp = thisAmp;
|
||||||
sample_count = 0;
|
sample_count = 0;
|
||||||
null_count = 0;
|
|
||||||
bit_count = 0;
|
bit_count = 0;
|
||||||
frame.clear();
|
frame.clear();
|
||||||
|
|
||||||
// Compute preamble pulses power to set thresholds
|
|
||||||
threshold = (shifter[0].first + shifter[2].first + shifter[7].first + shifter[9].first) / 4;
|
|
||||||
threshold_high = threshold * 1.414; // +3dB
|
|
||||||
threshold_low = threshold * 0.707; // -3dB
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} // 4 & 5 low and 11-14 low
|
||||||
|
} // Check for preamble pattern
|
||||||
|
|
||||||
|
// Store mag for next time
|
||||||
prev_mag = mag;
|
prev_mag = mag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ADSBRXProcessor::on_message(const Message* const message) {
|
void ADSBRXProcessor::on_message(const Message* const message) {
|
||||||
if (message->id == Message::ID::ADSBConfigure) {
|
if (message->id == Message::ID::ADSBConfigure) {
|
||||||
null_count = 0;
|
|
||||||
bit_count = 0;
|
bit_count = 0;
|
||||||
sample_count = 0;
|
sample_count = 0;
|
||||||
decoding = false;
|
decoding = false;
|
||||||
@ -148,8 +158,10 @@ void ADSBRXProcessor::on_message(const Message* const message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
int main() {
|
int main() {
|
||||||
EventDispatcher event_dispatcher { std::make_unique<ADSBRXProcessor>() };
|
EventDispatcher event_dispatcher { std::make_unique<ADSBRXProcessor>() };
|
||||||
event_dispatcher.run();
|
event_dispatcher.run();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
@ -40,8 +40,6 @@ public:
|
|||||||
void on_message(const Message* const message) override;
|
void on_message(const Message* const message) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr float k = 1.0f / 128.0f;
|
|
||||||
|
|
||||||
static constexpr size_t baseband_fs = 2000000;
|
static constexpr size_t baseband_fs = 2000000;
|
||||||
|
|
||||||
BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Receive };
|
BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Receive };
|
||||||
@ -49,16 +47,17 @@ private:
|
|||||||
|
|
||||||
ADSBFrame frame { };
|
ADSBFrame frame { };
|
||||||
bool configured { false };
|
bool configured { false };
|
||||||
float prev_mag { 0 };
|
uint32_t prev_mag { 0 };
|
||||||
float threshold { }, threshold_low { }, threshold_high { };
|
size_t bit_count { 0 }, sample_count { 0 };
|
||||||
size_t null_count { 0 }, bit_count { 0 }, sample_count { 0 };
|
size_t msgLen{ 112 };
|
||||||
std::pair<float, uint8_t> shifter[ADSB_PREAMBLE_LENGTH];
|
uint32_t shifter[ADSB_PREAMBLE_LENGTH+1];
|
||||||
bool decoding { };
|
bool decoding { };
|
||||||
bool preamble { }, active { };
|
bool preamble { }, active { };
|
||||||
uint16_t bit_pos { 0 };
|
uint16_t bit_pos { 0 };
|
||||||
uint8_t cur_bit { 0 };
|
uint8_t cur_bit { 0 };
|
||||||
uint32_t sample { 0 };
|
uint32_t sample { 0 };
|
||||||
int8_t re { }, im { };
|
int32_t re { }, im { };
|
||||||
|
int32_t amp {0};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -376,13 +376,16 @@ public:
|
|||||||
class ADSBFrameMessage : public Message {
|
class ADSBFrameMessage : public Message {
|
||||||
public:
|
public:
|
||||||
constexpr ADSBFrameMessage(
|
constexpr ADSBFrameMessage(
|
||||||
const adsb::ADSBFrame& frame
|
const adsb::ADSBFrame& frame,
|
||||||
|
const uint32_t amp
|
||||||
) : Message { ID::ADSBFrame },
|
) : Message { ID::ADSBFrame },
|
||||||
frame { frame }
|
frame { frame },
|
||||||
|
amp(amp)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
adsb::ADSBFrame frame;
|
adsb::ADSBFrame frame;
|
||||||
|
uint32_t amp;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AFSKDataMessage : public Message {
|
class AFSKDataMessage : public Message {
|
||||||
|
6231
firmware/tools/airlines.csv.txt
Normal file
6231
firmware/tools/airlines.csv.txt
Normal file
File diff suppressed because it is too large
Load Diff
4
firmware/tools/airlines.csv.txtZone.Identifier
Normal file
4
firmware/tools/airlines.csv.txtZone.Identifier
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[ZoneTransfer]
|
||||||
|
ZoneId=3
|
||||||
|
ReferrerUrl=https://www.bountysource.com/
|
||||||
|
HostUrl=https://github-repository-files.githubusercontent.com/251043704/4747359?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20211011%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20211011T232519Z&X-Amz-Expires=300&X-Amz-Signature=25180babeea757c128d1a995735486006e018abe6941ab5493597d194dc7b994&X-Amz-SignedHeaders=host&actor_id=21973866&key_id=0&repo_id=251043704&response-content-disposition=attachment%3Bfilename%3Dairlines.csv.txt&response-content-type=text%2Fplain
|
@ -24,7 +24,7 @@ import struct
|
|||||||
outfile = open("airlines.db", "w")
|
outfile = open("airlines.db", "w")
|
||||||
|
|
||||||
# Download airlines.txt from http://xdeco.org/?page_id=30
|
# Download airlines.txt from http://xdeco.org/?page_id=30
|
||||||
lines = [line.rstrip('\n') for line in open('../../sdcard/ADSB/airlines.txt', 'r')]
|
lines = [line.rstrip('\n') for line in open('../../sdcard/ADSB/airlines.csv.txt', 'r')]
|
||||||
n = 0
|
n = 0
|
||||||
|
|
||||||
for line in lines:
|
for line in lines:
|
||||||
|
Loading…
Reference in New Issue
Block a user