adding support for rtl-sdr tunner
This commit is contained in:
@@ -0,0 +1,140 @@
|
|||||||
|
import sys
|
||||||
|
import numpy as np
|
||||||
|
import pyModeS as pms
|
||||||
|
from rtlsdr import RtlSdr
|
||||||
|
from threading import Thread
|
||||||
|
import time
|
||||||
|
|
||||||
|
amplitude_threshold = 0.2
|
||||||
|
modes_sample_rate = 2e6
|
||||||
|
modes_frequency = 1090e6
|
||||||
|
buffer_size = 1024 * 100
|
||||||
|
read_size = 1024 * 8
|
||||||
|
pbits = 8
|
||||||
|
fbits = 112
|
||||||
|
preamble = "1010000101000000"
|
||||||
|
|
||||||
|
|
||||||
|
class RtlReader(Thread):
|
||||||
|
def __init__(self, debug=False):
|
||||||
|
super(RtlReader, self).__init__()
|
||||||
|
self.signal_buffer = np.array([])
|
||||||
|
self.debug = debug
|
||||||
|
self.sdr = RtlSdr()
|
||||||
|
self.sdr.sample_rate = modes_sample_rate
|
||||||
|
self.sdr.center_freq = modes_frequency
|
||||||
|
self.sdr.gain = "auto"
|
||||||
|
# sdr.freq_correction = 75
|
||||||
|
|
||||||
|
def _process_buffer(self):
|
||||||
|
messages = []
|
||||||
|
|
||||||
|
pulses_array = np.where(self.signal_buffer < amplitude_threshold, 0, 1)
|
||||||
|
pulses = "".join(str(x) for x in pulses_array)
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
while i < len(pulses):
|
||||||
|
if pulses[i] == 0:
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
if pulses[i : i + pbits * 2] == preamble:
|
||||||
|
frame_start = i + pbits * 2
|
||||||
|
frame_end = i + pbits * 2 + (fbits + 1) * 2
|
||||||
|
frame_pulses = pulses[frame_start:frame_end]
|
||||||
|
|
||||||
|
msgbin = ""
|
||||||
|
for j in range(0, len(frame_pulses), 2):
|
||||||
|
p2 = frame_pulses[j : j + 2]
|
||||||
|
if p2 == "10":
|
||||||
|
c = "1"
|
||||||
|
elif p2 == "01":
|
||||||
|
c = "0"
|
||||||
|
elif p2 == "11":
|
||||||
|
a2 = self.signal_buffer[
|
||||||
|
frame_start + j : frame_start + j + 2
|
||||||
|
]
|
||||||
|
if a2[0] > a2[1]:
|
||||||
|
c = "1"
|
||||||
|
else:
|
||||||
|
c = "0"
|
||||||
|
elif p2 == "00":
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
msgbin = ""
|
||||||
|
break
|
||||||
|
msgbin += c
|
||||||
|
|
||||||
|
# advance i with a jump
|
||||||
|
i = frame_start + j
|
||||||
|
|
||||||
|
if len(msgbin) > 0:
|
||||||
|
msghex = pms.bin2hex(msgbin)
|
||||||
|
if self._check_msg(msghex):
|
||||||
|
messages.append([msghex, time.time()])
|
||||||
|
if self.debug:
|
||||||
|
self._debug_msg(msghex)
|
||||||
|
|
||||||
|
elif i > len(self.signal_buffer) - pbits * 2 - fbits * 2:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
# keep reminder of buffer for next iteration
|
||||||
|
self.signal_buffer = self.signal_buffer[i:]
|
||||||
|
return messages
|
||||||
|
|
||||||
|
def _check_msg(self, msg):
|
||||||
|
df = pms.df(msg)
|
||||||
|
msglen = len(msg)
|
||||||
|
if df == 17 and msglen == 28:
|
||||||
|
if pms.crc(msg) == 0:
|
||||||
|
return True
|
||||||
|
elif df in [20, 21] and msglen == 28:
|
||||||
|
return True
|
||||||
|
elif df in [4, 5, 11] and msglen == 14:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _debug_msg(self, msg):
|
||||||
|
df = pms.df(msg)
|
||||||
|
msglen = len(msg)
|
||||||
|
if df == 17 and msglen == 28:
|
||||||
|
print(msg, pms.icao(msg), pms.crc(msg))
|
||||||
|
elif df in [20, 21] and msglen == 28:
|
||||||
|
print(msg, pms.icao(msg))
|
||||||
|
elif df in [4, 5, 11] and msglen == 14:
|
||||||
|
print(msg, pms.icao(msg))
|
||||||
|
else:
|
||||||
|
print("[*]", msg)
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _read_callback(self, data, rtlsdr_obj):
|
||||||
|
self.signal_buffer = np.concatenate(
|
||||||
|
(self.signal_buffer, np.absolute(data))
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(self.signal_buffer) >= buffer_size:
|
||||||
|
try:
|
||||||
|
messages = self._process_buffer()
|
||||||
|
self.handle_messages(messages)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def handle_messages(self, messages):
|
||||||
|
"""re-implement this method to handle the messages"""
|
||||||
|
for msg, t in messages:
|
||||||
|
pass
|
||||||
|
# print("%15.9f %s" % (t, msg))
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.sdr.read_samples_async(self._read_callback, read_size)
|
||||||
|
# while True:
|
||||||
|
# data = self.sdr.read_samples(read_size)
|
||||||
|
# self._read_callback(data, None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
rtl = RtlReader()
|
||||||
|
rtl.debug = True
|
||||||
|
# rtl.daemon = True
|
||||||
|
rtl.start()
|
||||||
+55
-52
@@ -1,6 +1,6 @@
|
|||||||
'''
|
"""
|
||||||
Stream beast raw data from a TCP server, convert to mode-s messages
|
Stream beast raw data from a TCP server, convert to mode-s messages
|
||||||
'''
|
"""
|
||||||
from __future__ import print_function, division
|
from __future__ import print_function, division
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
@@ -9,36 +9,31 @@ import time
|
|||||||
import pyModeS as pms
|
import pyModeS as pms
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
import traceback
|
import traceback
|
||||||
|
import zmq
|
||||||
|
|
||||||
if (sys.version_info > (3, 0)):
|
if sys.version_info > (3, 0):
|
||||||
PY_VERSION = 3
|
PY_VERSION = 3
|
||||||
else:
|
else:
|
||||||
PY_VERSION = 2
|
PY_VERSION = 2
|
||||||
|
|
||||||
|
|
||||||
class BaseClient(Thread):
|
class BaseClient(Thread):
|
||||||
def __init__(self, host, port, rawtype):
|
def __init__(self, host, port, rawtype):
|
||||||
Thread.__init__(self)
|
Thread.__init__(self)
|
||||||
self.host = host
|
self.host = host
|
||||||
self.port = port
|
self.port = port
|
||||||
self.buffer = []
|
self.buffer = []
|
||||||
|
self.socket = None
|
||||||
self.rawtype = rawtype
|
self.rawtype = rawtype
|
||||||
if self.rawtype not in ['avr', 'beast', 'skysense']:
|
if self.rawtype not in ["avr", "beast", "skysense"]:
|
||||||
print("rawtype must be either avr, beast or skysense")
|
print("rawtype must be either avr, beast or skysense")
|
||||||
os._exit(1)
|
os._exit(1)
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
while True:
|
self.socket = zmq.Context().socket(zmq.STREAM)
|
||||||
try:
|
self.socket.setsockopt(zmq.LINGER, 0)
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
self.socket.setsockopt(zmq.RCVTIMEO, 2000)
|
||||||
s.settimeout(10) # 10 second timeout
|
self.socket.connect("tcp://%s:%s" % (self.host, self.port))
|
||||||
s.connect((self.host, self.port))
|
|
||||||
print("Server connected - %s:%s" % (self.host, self.port))
|
|
||||||
print("collecting ADS-B messages...")
|
|
||||||
return s
|
|
||||||
except socket.error as err:
|
|
||||||
print("Socket connection error: %s. reconnecting..." % err)
|
|
||||||
time.sleep(3)
|
|
||||||
|
|
||||||
|
|
||||||
def read_avr_buffer(self):
|
def read_avr_buffer(self):
|
||||||
# -- testing --
|
# -- testing --
|
||||||
@@ -57,9 +52,9 @@ class BaseClient(Thread):
|
|||||||
messages.append([self.current_msg, ts])
|
messages.append([self.current_msg, ts])
|
||||||
if b == 42:
|
if b == 42:
|
||||||
msg_stop = False
|
msg_stop = False
|
||||||
self.current_msg = ''
|
self.current_msg = ""
|
||||||
|
|
||||||
if (not msg_stop) and (48<=b<=57 or 65<=b<=70 or 97<=b<=102):
|
if (not msg_stop) and (48 <= b <= 57 or 65 <= b <= 70 or 97 <= b <= 102):
|
||||||
self.current_msg = self.current_msg + chr(b)
|
self.current_msg = self.current_msg + chr(b)
|
||||||
|
|
||||||
self.buffer = []
|
self.buffer = []
|
||||||
@@ -67,7 +62,7 @@ class BaseClient(Thread):
|
|||||||
return messages
|
return messages
|
||||||
|
|
||||||
def read_beast_buffer(self):
|
def read_beast_buffer(self):
|
||||||
'''
|
"""
|
||||||
<esc> "1" : 6 byte MLAT timestamp, 1 byte signal level,
|
<esc> "1" : 6 byte MLAT timestamp, 1 byte signal level,
|
||||||
2 byte Mode-AC
|
2 byte Mode-AC
|
||||||
<esc> "2" : 6 byte MLAT timestamp, 1 byte signal level,
|
<esc> "2" : 6 byte MLAT timestamp, 1 byte signal level,
|
||||||
@@ -81,7 +76,7 @@ class BaseClient(Thread):
|
|||||||
|
|
||||||
timestamp:
|
timestamp:
|
||||||
wiki.modesbeast.com/Radarcape:Firmware_Versions#The_GPS_timestamp
|
wiki.modesbeast.com/Radarcape:Firmware_Versions#The_GPS_timestamp
|
||||||
'''
|
"""
|
||||||
|
|
||||||
messages_mlat = []
|
messages_mlat = []
|
||||||
msg = []
|
msg = []
|
||||||
@@ -91,16 +86,16 @@ class BaseClient(Thread):
|
|||||||
# then, reset the self.buffer with the remainder
|
# then, reset the self.buffer with the remainder
|
||||||
|
|
||||||
while i < len(self.buffer):
|
while i < len(self.buffer):
|
||||||
if (self.buffer[i:i+2] == [0x1a, 0x1a]):
|
if self.buffer[i : i + 2] == [0x1A, 0x1A]:
|
||||||
msg.append(0x1a)
|
msg.append(0x1A)
|
||||||
i += 1
|
i += 1
|
||||||
elif (i == len(self.buffer) - 1) and (self.buffer[i] == 0x1a):
|
elif (i == len(self.buffer) - 1) and (self.buffer[i] == 0x1A):
|
||||||
# special case where the last bit is 0x1a
|
# special case where the last bit is 0x1a
|
||||||
msg.append(0x1a)
|
msg.append(0x1A)
|
||||||
elif self.buffer[i] == 0x1a:
|
elif self.buffer[i] == 0x1A:
|
||||||
if i == len(self.buffer) - 1:
|
if i == len(self.buffer) - 1:
|
||||||
# special case where the last bit is 0x1a
|
# special case where the last bit is 0x1a
|
||||||
msg.append(0x1a)
|
msg.append(0x1A)
|
||||||
elif len(msg) > 0:
|
elif len(msg) > 0:
|
||||||
messages_mlat.append(msg)
|
messages_mlat.append(msg)
|
||||||
msg = []
|
msg = []
|
||||||
@@ -112,12 +107,12 @@ class BaseClient(Thread):
|
|||||||
if len(msg) > 0:
|
if len(msg) > 0:
|
||||||
reminder = []
|
reminder = []
|
||||||
for i, m in enumerate(msg):
|
for i, m in enumerate(msg):
|
||||||
if (m == 0x1a) and (i < len(msg)-1):
|
if (m == 0x1A) and (i < len(msg) - 1):
|
||||||
# rewind 0x1a, except when it is at the last bit
|
# rewind 0x1a, except when it is at the last bit
|
||||||
reminder.extend([m, m])
|
reminder.extend([m, m])
|
||||||
else:
|
else:
|
||||||
reminder.append(m)
|
reminder.append(m)
|
||||||
self.buffer = [0x1a] + msg
|
self.buffer = [0x1A] + msg
|
||||||
else:
|
else:
|
||||||
self.buffer = []
|
self.buffer = []
|
||||||
|
|
||||||
@@ -131,10 +126,10 @@ class BaseClient(Thread):
|
|||||||
|
|
||||||
if msgtype == 0x32:
|
if msgtype == 0x32:
|
||||||
# Mode-S Short Message, 7 byte, 14-len hexstr
|
# Mode-S Short Message, 7 byte, 14-len hexstr
|
||||||
msg = ''.join('%02X' % i for i in mm[8:15])
|
msg = "".join("%02X" % i for i in mm[8:15])
|
||||||
elif msgtype == 0x33:
|
elif msgtype == 0x33:
|
||||||
# Mode-S Long Message, 14 byte, 28-len hexstr
|
# Mode-S Long Message, 14 byte, 28-len hexstr
|
||||||
msg = ''.join('%02X' % i for i in mm[8:22])
|
msg = "".join("%02X" % i for i in mm[8:22])
|
||||||
else:
|
else:
|
||||||
# Other message tupe
|
# Other message tupe
|
||||||
continue
|
continue
|
||||||
@@ -215,25 +210,33 @@ class BaseClient(Thread):
|
|||||||
messages = []
|
messages = []
|
||||||
while len(self.buffer) > SS_MSGLENGTH:
|
while len(self.buffer) > SS_MSGLENGTH:
|
||||||
i = 0
|
i = 0
|
||||||
if self.buffer[i] == SS_STARTCHAR and self.buffer[i+SS_MSGLENGTH] == SS_STARTCHAR:
|
if (
|
||||||
|
self.buffer[i] == SS_STARTCHAR
|
||||||
|
and self.buffer[i + SS_MSGLENGTH] == SS_STARTCHAR
|
||||||
|
):
|
||||||
i += 1
|
i += 1
|
||||||
if (self.buffer[i]>>7):
|
if self.buffer[i] >> 7:
|
||||||
#Long message
|
# Long message
|
||||||
payload = self.buffer[i:i+14]
|
payload = self.buffer[i : i + 14]
|
||||||
else:
|
else:
|
||||||
#Short message
|
# Short message
|
||||||
payload = self.buffer[i:i+7]
|
payload = self.buffer[i : i + 7]
|
||||||
msg = ''.join('%02X' % j for j in payload)
|
msg = "".join("%02X" % j for j in payload)
|
||||||
i += 14 #Both message types use 14 bytes
|
i += 14 # Both message types use 14 bytes
|
||||||
tsbin = self.buffer[i:i+6]
|
tsbin = self.buffer[i : i + 6]
|
||||||
sec = ( (tsbin[0] & 0x7f) << 10) | (tsbin[1] << 2 ) | (tsbin[2] >> 6)
|
sec = ((tsbin[0] & 0x7F) << 10) | (tsbin[1] << 2) | (tsbin[2] >> 6)
|
||||||
nano = ( (tsbin[2] & 0x3f) << 24) | (tsbin[3] << 16) | (tsbin[4] << 8) | tsbin[5]
|
nano = (
|
||||||
ts = sec + nano*1.0e-9
|
((tsbin[2] & 0x3F) << 24)
|
||||||
|
| (tsbin[3] << 16)
|
||||||
|
| (tsbin[4] << 8)
|
||||||
|
| tsbin[5]
|
||||||
|
)
|
||||||
|
ts = sec + nano * 1.0e-9
|
||||||
i += 6
|
i += 6
|
||||||
#Signal and noise level - Don't care for now
|
# Signal and noise level - Don't care for now
|
||||||
i += 3
|
i += 3
|
||||||
self.buffer = self.buffer[SS_MSGLENGTH:]
|
self.buffer = self.buffer[SS_MSGLENGTH:]
|
||||||
messages.append( [msg,ts] )
|
messages.append([msg, ts])
|
||||||
else:
|
else:
|
||||||
self.buffer = self.buffer[1:]
|
self.buffer = self.buffer[1:]
|
||||||
return messages
|
return messages
|
||||||
@@ -244,11 +247,11 @@ class BaseClient(Thread):
|
|||||||
print("%15.9f %s" % (t, msg))
|
print("%15.9f %s" % (t, msg))
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
sock = self.connect()
|
self.connect()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
received = sock.recv(1024)
|
received = [i for i in self.socket.recv(4096)]
|
||||||
|
|
||||||
if PY_VERSION == 2:
|
if PY_VERSION == 2:
|
||||||
received = [ord(i) for i in received]
|
received = [ord(i) for i in received]
|
||||||
@@ -261,11 +264,11 @@ class BaseClient(Thread):
|
|||||||
# continue
|
# continue
|
||||||
# -- Removed!! Cause delay in low data rate scenario --
|
# -- Removed!! Cause delay in low data rate scenario --
|
||||||
|
|
||||||
if self.rawtype == 'beast':
|
if self.rawtype == "beast":
|
||||||
messages = self.read_beast_buffer()
|
messages = self.read_beast_buffer()
|
||||||
elif self.rawtype == 'avr':
|
elif self.rawtype == "avr":
|
||||||
messages = self.read_avr_buffer()
|
messages = self.read_avr_buffer()
|
||||||
elif self.rawtype == 'skysense':
|
elif self.rawtype == "skysense":
|
||||||
messages = self.read_skysense_buffer()
|
messages = self.read_skysense_buffer()
|
||||||
|
|
||||||
if not messages:
|
if not messages:
|
||||||
@@ -279,8 +282,8 @@ class BaseClient(Thread):
|
|||||||
# Provides the user an option to supply the environment
|
# Provides the user an option to supply the environment
|
||||||
# variable PYMODES_DEBUG to halt the execution
|
# variable PYMODES_DEBUG to halt the execution
|
||||||
# for debugging purposes
|
# for debugging purposes
|
||||||
debug_intent = os.environ.get('PYMODES_DEBUG', 'false')
|
debug_intent = os.environ.get("PYMODES_DEBUG", "false")
|
||||||
if debug_intent.lower() == 'true':
|
if debug_intent.lower() == "true":
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
sys.exit()
|
sys.exit()
|
||||||
else:
|
else:
|
||||||
@@ -292,7 +295,7 @@ class BaseClient(Thread):
|
|||||||
print("Unexpected Error:", e)
|
print("Unexpected Error:", e)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
# for testing purpose only
|
# for testing purpose only
|
||||||
host = sys.argv[1]
|
host = sys.argv[1]
|
||||||
port = int(sys.argv[2])
|
port = int(sys.argv[2])
|
||||||
|
|||||||
+100
-19
@@ -9,6 +9,7 @@ import curses
|
|||||||
from threading import Lock
|
from threading import Lock
|
||||||
import pyModeS as pms
|
import pyModeS as pms
|
||||||
from pyModeS.extra.tcpclient import BaseClient
|
from pyModeS.extra.tcpclient import BaseClient
|
||||||
|
from pyModeS.extra.rtlreader import RtlReader
|
||||||
from pyModeS.streamer.stream import Stream
|
from pyModeS.streamer.stream import Stream
|
||||||
from pyModeS.streamer.screen import Screen
|
from pyModeS.streamer.screen import Screen
|
||||||
|
|
||||||
@@ -19,29 +20,67 @@ COMMB_MSG = []
|
|||||||
COMMB_TS = []
|
COMMB_TS = []
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument('--server', help='server address or IP', required=True)
|
parser.add_argument(
|
||||||
parser.add_argument('--port', help='raw data port', required=True)
|
"--source", help="rtlsdr or tcp", required=True, default="tcp"
|
||||||
parser.add_argument('--rawtype', help='beast, avr or skysense', required=True)
|
)
|
||||||
parser.add_argument('--latlon', help='receiver position', nargs=2, metavar=('LAT', 'LON'), required=True)
|
parser.add_argument("--server", help="server address or IP", default=None)
|
||||||
parser.add_argument('--show-uncertainty', dest='uncertainty', help='display uncertaint values, default off', action='store_true', required=False, default=False)
|
parser.add_argument("--port", help="raw data port", default=None)
|
||||||
parser.add_argument('--dumpto', help='folder to dump decoded output', required=False, default=None)
|
parser.add_argument("--rawtype", help="beast, avr or skysense", default=None)
|
||||||
|
parser.add_argument(
|
||||||
|
"--latlon",
|
||||||
|
help="receiver position",
|
||||||
|
nargs=2,
|
||||||
|
metavar=("LAT", "LON"),
|
||||||
|
required=True,
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--show-uncertainty",
|
||||||
|
dest="uncertainty",
|
||||||
|
help="display uncertaint values, default off",
|
||||||
|
action="store_true",
|
||||||
|
required=False,
|
||||||
|
default=False,
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--dumpto",
|
||||||
|
help="folder to dump decoded output",
|
||||||
|
required=False,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
SOURCE = args.source
|
||||||
SERVER = args.server
|
SERVER = args.server
|
||||||
PORT = int(args.port)
|
PORT = args.port
|
||||||
RAWTYPE = args.rawtype
|
RAWTYPE = args.rawtype
|
||||||
LAT0 = float(args.latlon[0])
|
LAT0 = float(args.latlon[0])
|
||||||
LON0 = float(args.latlon[1])
|
LON0 = float(args.latlon[1])
|
||||||
UNCERTAINTY = args.uncertainty
|
UNCERTAINTY = args.uncertainty
|
||||||
DUMPTO = args.dumpto
|
DUMPTO = args.dumpto
|
||||||
|
|
||||||
|
if SOURCE == "rtlsdr":
|
||||||
|
pass
|
||||||
|
elif SOURCE == "tcp":
|
||||||
|
if SERVER is None:
|
||||||
|
print("You must specify the server for TCP source.")
|
||||||
|
sys.exit(1)
|
||||||
|
if PORT is None:
|
||||||
|
print("You must specify the port for TCP source.")
|
||||||
|
sys.exit(1)
|
||||||
|
if RAWTYPE is None:
|
||||||
|
print("You must specify the rawtype for TCP source.")
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
print("Source must be rtlsdr or tcp.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
if DUMPTO is not None:
|
if DUMPTO is not None:
|
||||||
# append to current folder except root is given
|
# append to current folder except root is given
|
||||||
if DUMPTO[0] != '/':
|
if DUMPTO[0] != "/":
|
||||||
DUMPTO = os.getcwd() + '/' + DUMPTO
|
DUMPTO = os.getcwd() + "/" + DUMPTO
|
||||||
|
|
||||||
if not os.path.isdir(DUMPTO):
|
if not os.path.isdir(DUMPTO):
|
||||||
print('Error: dump folder (%s) does not exist' % DUMPTO)
|
print("Error: dump folder (%s) does not exist" % DUMPTO)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
@@ -56,7 +95,7 @@ class ModesClient(BaseClient):
|
|||||||
local_buffer_ehs_ts = []
|
local_buffer_ehs_ts = []
|
||||||
|
|
||||||
for msg, t in messages:
|
for msg, t in messages:
|
||||||
if len(msg) < 28: # only process long messages
|
if len(msg) < 28: # only process long messages
|
||||||
continue
|
continue
|
||||||
|
|
||||||
df = pms.df(msg)
|
df = pms.df(msg)
|
||||||
@@ -70,7 +109,6 @@ class ModesClient(BaseClient):
|
|||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
||||||
LOCK.acquire()
|
LOCK.acquire()
|
||||||
ADSB_MSG.extend(local_buffer_adsb_msg)
|
ADSB_MSG.extend(local_buffer_adsb_msg)
|
||||||
ADSB_TS.extend(local_buffer_adsb_ts)
|
ADSB_TS.extend(local_buffer_adsb_ts)
|
||||||
@@ -79,12 +117,55 @@ class ModesClient(BaseClient):
|
|||||||
LOCK.release()
|
LOCK.release()
|
||||||
|
|
||||||
|
|
||||||
# redirect all stdout to null, avoiding messing up with the screen
|
class ModesRtlReader(RtlReader):
|
||||||
sys.stdout = open(os.devnull, 'w')
|
"""docstring for ModesRtlReader."""
|
||||||
|
|
||||||
client = ModesClient(host=SERVER, port=PORT, rawtype=RAWTYPE)
|
def __init__(self):
|
||||||
client.daemon = True
|
super(ModesRtlReader, self).__init__()
|
||||||
client.start()
|
|
||||||
|
def handle_messages(self, messages):
|
||||||
|
local_buffer_adsb_msg = []
|
||||||
|
local_buffer_adsb_ts = []
|
||||||
|
local_buffer_ehs_msg = []
|
||||||
|
local_buffer_ehs_ts = []
|
||||||
|
|
||||||
|
for msg, t in messages:
|
||||||
|
if len(msg) < 28: # only process long messages
|
||||||
|
continue
|
||||||
|
|
||||||
|
df = pms.df(msg)
|
||||||
|
|
||||||
|
if df == 17 or df == 18:
|
||||||
|
local_buffer_adsb_msg.append(msg)
|
||||||
|
local_buffer_adsb_ts.append(t)
|
||||||
|
elif df == 20 or df == 21:
|
||||||
|
local_buffer_ehs_msg.append(msg)
|
||||||
|
local_buffer_ehs_ts.append(t)
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
|
LOCK.acquire()
|
||||||
|
ADSB_MSG.extend(local_buffer_adsb_msg)
|
||||||
|
ADSB_TS.extend(local_buffer_adsb_ts)
|
||||||
|
COMMB_MSG.extend(local_buffer_ehs_msg)
|
||||||
|
COMMB_TS.extend(local_buffer_ehs_ts)
|
||||||
|
# print(len(ADSB_MSG))
|
||||||
|
# print(len(COMMB_MSG))
|
||||||
|
LOCK.release()
|
||||||
|
|
||||||
|
|
||||||
|
# redirect all stdout to null, avoiding messing up with the screen
|
||||||
|
sys.stdout = open(os.devnull, "w")
|
||||||
|
|
||||||
|
if SOURCE == "tcp":
|
||||||
|
client = ModesClient(host=SERVER, port=PORT, rawtype=RAWTYPE)
|
||||||
|
client.daemon = True
|
||||||
|
client.start()
|
||||||
|
elif SOURCE == "rtlsdr":
|
||||||
|
rtl = ModesRtlReader()
|
||||||
|
# rtl.debug = True
|
||||||
|
rtl.daemon = True
|
||||||
|
rtl.start()
|
||||||
|
|
||||||
stream = Stream(lat0=LAT0, lon0=LON0, dumpto=DUMPTO)
|
stream = Stream(lat0=LAT0, lon0=LON0, dumpto=DUMPTO)
|
||||||
|
|
||||||
@@ -94,7 +175,7 @@ try:
|
|||||||
screen.start()
|
screen.start()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
if len(ADSB_MSG) > 200:
|
if len(ADSB_MSG) > 1:
|
||||||
LOCK.acquire()
|
LOCK.acquire()
|
||||||
stream.process_raw(ADSB_TS, ADSB_MSG, COMMB_TS, COMMB_MSG)
|
stream.process_raw(ADSB_TS, ADSB_MSG, COMMB_TS, COMMB_MSG)
|
||||||
ADSB_MSG = []
|
ADSB_MSG = []
|
||||||
@@ -107,7 +188,7 @@ try:
|
|||||||
try:
|
try:
|
||||||
screen.update_data(acs)
|
screen.update_data(acs)
|
||||||
screen.update()
|
screen.update()
|
||||||
time.sleep(0.02)
|
time.sleep(1)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
raise
|
raise
|
||||||
except:
|
except:
|
||||||
|
|||||||
+55
-49
@@ -6,38 +6,39 @@ import time
|
|||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
|
||||||
COLUMNS = [
|
COLUMNS = [
|
||||||
('call', 10),
|
("call", 10),
|
||||||
('lat', 10),
|
("lat", 10),
|
||||||
('lon', 10),
|
("lon", 10),
|
||||||
('alt', 7),
|
("alt", 7),
|
||||||
('gs', 5),
|
("gs", 5),
|
||||||
('tas', 5),
|
("tas", 5),
|
||||||
('ias', 5),
|
("ias", 5),
|
||||||
('mach', 7),
|
("mach", 7),
|
||||||
('roc', 7),
|
("roc", 7),
|
||||||
('trk', 10),
|
("trk", 10),
|
||||||
('hdg', 10),
|
("hdg", 10),
|
||||||
('live', 6),
|
("live", 6),
|
||||||
]
|
]
|
||||||
|
|
||||||
UNCERTAINTY_COLUMNS = [
|
UNCERTAINTY_COLUMNS = [
|
||||||
('|', 5),
|
("|", 5),
|
||||||
('ver', 4),
|
("ver", 4),
|
||||||
('HPL', 5),
|
("HPL", 5),
|
||||||
('RCu', 5),
|
("RCu", 5),
|
||||||
('RCv', 5),
|
("RCv", 5),
|
||||||
('HVE', 5),
|
("HVE", 5),
|
||||||
('VVE', 5),
|
("VVE", 5),
|
||||||
('Rc', 4),
|
("Rc", 4),
|
||||||
('VPL', 5),
|
("VPL", 5),
|
||||||
('EPU', 5),
|
("EPU", 5),
|
||||||
('VEPU', 6),
|
("VEPU", 6),
|
||||||
('HFOMr', 7),
|
("HFOMr", 7),
|
||||||
('VFOMr', 7),
|
("VFOMr", 7),
|
||||||
('PE_RCu', 8),
|
("PE_RCu", 8),
|
||||||
('PE_VPL', 8),
|
("PE_VPL", 8),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class Screen(Thread):
|
class Screen(Thread):
|
||||||
def __init__(self, uncertainty=False):
|
def __init__(self, uncertainty=False):
|
||||||
Thread.__init__(self)
|
Thread.__init__(self)
|
||||||
@@ -55,7 +56,6 @@ class Screen(Thread):
|
|||||||
if uncertainty:
|
if uncertainty:
|
||||||
self.columns.extend(UNCERTAINTY_COLUMNS)
|
self.columns.extend(UNCERTAINTY_COLUMNS)
|
||||||
|
|
||||||
|
|
||||||
def reset_cursor_pos(self):
|
def reset_cursor_pos(self):
|
||||||
self.screen.move(self.y, self.x)
|
self.screen.move(self.y, self.x)
|
||||||
|
|
||||||
@@ -64,7 +64,12 @@ class Screen(Thread):
|
|||||||
|
|
||||||
def draw_frame(self):
|
def draw_frame(self):
|
||||||
self.screen.border(0)
|
self.screen.border(0)
|
||||||
self.screen.addstr(0, 2, "Online aircraft [%d] ('Ctrl+C' to exit, 'Enter' to lock one)" % len(self.acs))
|
self.screen.addstr(
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
"Online aircraft [%d] ('Ctrl+C' to exit, 'Enter' to lock one)"
|
||||||
|
% len(self.acs),
|
||||||
|
)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
if len(self.acs) == 0:
|
if len(self.acs) == 0:
|
||||||
@@ -81,21 +86,20 @@ class Screen(Thread):
|
|||||||
|
|
||||||
row = 1
|
row = 1
|
||||||
|
|
||||||
header = ' icao'
|
header = " icao"
|
||||||
for c, cw in self.columns:
|
for c, cw in self.columns:
|
||||||
header += (cw-len(c))*' ' + c
|
header += (cw - len(c)) * " " + c
|
||||||
|
|
||||||
# fill end with spaces
|
# fill end with spaces
|
||||||
header += (self.scr_w - 2 - len(header)) * ' '
|
header += (self.scr_w - 2 - len(header)) * " "
|
||||||
|
|
||||||
if len(header) > self.scr_w - 2:
|
if len(header) > self.scr_w - 2:
|
||||||
header = header[:self.scr_w-3] + '>'
|
header = header[: self.scr_w - 3] + ">"
|
||||||
|
|
||||||
|
|
||||||
self.screen.addstr(row, 1, header)
|
self.screen.addstr(row, 1, header)
|
||||||
|
|
||||||
row +=1
|
row += 1
|
||||||
self.screen.addstr(row, 1, '-'*(self.scr_w-2))
|
self.screen.addstr(row, 1, "-" * (self.scr_w - 2))
|
||||||
|
|
||||||
icaos = np.array(list(self.acs.keys()))
|
icaos = np.array(list(self.acs.keys()))
|
||||||
icaos = np.sort(icaos)
|
icaos = np.sort(icaos)
|
||||||
@@ -105,10 +109,10 @@ class Screen(Thread):
|
|||||||
idx = row + self.offset - 3
|
idx = row + self.offset - 3
|
||||||
|
|
||||||
if idx > len(icaos) - 1:
|
if idx > len(icaos) - 1:
|
||||||
line = ' '*(self.scr_w-2)
|
line = " " * (self.scr_w - 2)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
line = ''
|
line = ""
|
||||||
|
|
||||||
icao = icaos[idx]
|
icao = icaos[idx]
|
||||||
ac = self.acs[icao]
|
ac = self.acs[icao]
|
||||||
@@ -116,22 +120,22 @@ class Screen(Thread):
|
|||||||
line += icao
|
line += icao
|
||||||
|
|
||||||
for c, cw in self.columns:
|
for c, cw in self.columns:
|
||||||
if c=='|':
|
if c == "|":
|
||||||
val = '|'
|
val = "|"
|
||||||
elif c=='live':
|
elif c == "live":
|
||||||
val = str(int(time.time() - ac[c]))+'s'
|
val = str(ac[c] - int(time.time())) + "s"
|
||||||
elif ac[c] is None:
|
elif ac[c] is None:
|
||||||
val = ''
|
val = ""
|
||||||
else:
|
else:
|
||||||
val = ac[c]
|
val = ac[c]
|
||||||
val_str = str(val)
|
val_str = str(val)
|
||||||
line += (cw-len(val_str))*' ' + val_str
|
line += (cw - len(val_str)) * " " + val_str
|
||||||
|
|
||||||
# fill end with spaces
|
# fill end with spaces
|
||||||
line += (self.scr_w - 2 - len(line)) * ' '
|
line += (self.scr_w - 2 - len(line)) * " "
|
||||||
|
|
||||||
if len(line) > self.scr_w - 2:
|
if len(line) > self.scr_w - 2:
|
||||||
line = line[:self.scr_w-3] + '>'
|
line = line[: self.scr_w - 3] + ">"
|
||||||
|
|
||||||
if (icao is not None) and (self.lock_icao == icao):
|
if (icao is not None) and (self.lock_icao == icao):
|
||||||
self.screen.addstr(row, 1, line, curses.A_STANDOUT)
|
self.screen.addstr(row, 1, line, curses.A_STANDOUT)
|
||||||
@@ -140,11 +144,13 @@ class Screen(Thread):
|
|||||||
else:
|
else:
|
||||||
self.screen.addstr(row, 1, line)
|
self.screen.addstr(row, 1, line)
|
||||||
|
|
||||||
self.screen.addstr(self.scr_h-3, 1, '-'*(self.scr_w-2))
|
self.screen.addstr(self.scr_h - 3, 1, "-" * (self.scr_w - 2))
|
||||||
|
|
||||||
total_page = len(icaos) // (self.scr_h - 4) + 1
|
total_page = len(icaos) // (self.scr_h - 4) + 1
|
||||||
current_page = self.offset // (self.scr_h - 4) + 1
|
current_page = self.offset // (self.scr_h - 4) + 1
|
||||||
self.screen.addstr(self.scr_h-2, 1, '(%d / %d)' % (current_page, total_page))
|
self.screen.addstr(
|
||||||
|
self.scr_h - 2, 1, "(%d / %d)" % (current_page, total_page)
|
||||||
|
)
|
||||||
|
|
||||||
self.reset_cursor_pos()
|
self.reset_cursor_pos()
|
||||||
|
|
||||||
@@ -168,7 +174,7 @@ class Screen(Thread):
|
|||||||
self.offset = offset_intent
|
self.offset = offset_intent
|
||||||
else:
|
else:
|
||||||
self.offset = 0
|
self.offset = 0
|
||||||
elif c == curses.KEY_DOWN :
|
elif c == curses.KEY_DOWN:
|
||||||
y_intent = self.y + 1
|
y_intent = self.y + 1
|
||||||
if y_intent < self.scr_h - 3:
|
if y_intent < self.scr_h - 3:
|
||||||
self.y = y_intent
|
self.y = y_intent
|
||||||
|
|||||||
+114
-105
@@ -5,7 +5,8 @@ import datetime
|
|||||||
import csv
|
import csv
|
||||||
import pyModeS as pms
|
import pyModeS as pms
|
||||||
|
|
||||||
class Stream():
|
|
||||||
|
class Stream:
|
||||||
def __init__(self, lat0, lon0, dumpto=None):
|
def __init__(self, lat0, lon0, dumpto=None):
|
||||||
|
|
||||||
self.acs = dict()
|
self.acs = dict()
|
||||||
@@ -14,15 +15,13 @@ class Stream():
|
|||||||
self.lon0 = lon0
|
self.lon0 = lon0
|
||||||
|
|
||||||
self.t = 0
|
self.t = 0
|
||||||
self.cache_timeout = 60 # seconds
|
self.cache_timeout = 60 # seconds
|
||||||
|
|
||||||
|
|
||||||
if dumpto is not None and os.path.isdir(dumpto):
|
if dumpto is not None and os.path.isdir(dumpto):
|
||||||
self.dumpto = dumpto
|
self.dumpto = dumpto
|
||||||
else:
|
else:
|
||||||
self.dumpto = None
|
self.dumpto = None
|
||||||
|
|
||||||
|
|
||||||
def process_raw(self, adsb_ts, adsb_msgs, commb_ts, commb_msgs, tnow=None):
|
def process_raw(self, adsb_ts, adsb_msgs, commb_ts, commb_msgs, tnow=None):
|
||||||
"""process a chunk of adsb and commb messages recieved in the same
|
"""process a chunk of adsb and commb messages recieved in the same
|
||||||
time period.
|
time period.
|
||||||
@@ -42,43 +41,43 @@ class Stream():
|
|||||||
|
|
||||||
if icao not in self.acs:
|
if icao not in self.acs:
|
||||||
self.acs[icao] = {
|
self.acs[icao] = {
|
||||||
'live': None,
|
"live": None,
|
||||||
'call': None,
|
"call": None,
|
||||||
'lat': None,
|
"lat": None,
|
||||||
'lon': None,
|
"lon": None,
|
||||||
'alt': None,
|
"alt": None,
|
||||||
'gs': None,
|
"gs": None,
|
||||||
'trk': None,
|
"trk": None,
|
||||||
'roc': None,
|
"roc": None,
|
||||||
'tas': None,
|
"tas": None,
|
||||||
'roll': None,
|
"roll": None,
|
||||||
'rtrk': None,
|
"rtrk": None,
|
||||||
'ias': None,
|
"ias": None,
|
||||||
'mach': None,
|
"mach": None,
|
||||||
'hdg': None,
|
"hdg": None,
|
||||||
'ver' : None,
|
"ver": None,
|
||||||
'HPL' : None,
|
"HPL": None,
|
||||||
'RCu' : None,
|
"RCu": None,
|
||||||
'RCv' : None,
|
"RCv": None,
|
||||||
'HVE' : None,
|
"HVE": None,
|
||||||
'VVE' : None,
|
"VVE": None,
|
||||||
'Rc' : None,
|
"Rc": None,
|
||||||
'VPL' : None,
|
"VPL": None,
|
||||||
'EPU' : None,
|
"EPU": None,
|
||||||
'VEPU' : None,
|
"VEPU": None,
|
||||||
'HFOMr' : None,
|
"HFOMr": None,
|
||||||
'VFOMr' : None,
|
"VFOMr": None,
|
||||||
'PE_RCu' : None,
|
"PE_RCu": None,
|
||||||
'PE_VPL' : None,
|
"PE_VPL": None,
|
||||||
}
|
}
|
||||||
|
|
||||||
self.acs[icao]['t'] = t
|
self.acs[icao]["t"] = t
|
||||||
self.acs[icao]['live'] = int(t)
|
self.acs[icao]["live"] = int(t)
|
||||||
|
|
||||||
if 1 <= tc <= 4:
|
if 1 <= tc <= 4:
|
||||||
cs = pms.adsb.callsign(msg)
|
cs = pms.adsb.callsign(msg)
|
||||||
self.acs[icao]['call'] = cs
|
self.acs[icao]["call"] = cs
|
||||||
output_buffer.append([t, icao, 'cs', cs])
|
output_buffer.append([t, icao, "cs", cs])
|
||||||
|
|
||||||
if (5 <= tc <= 8) or (tc == 19):
|
if (5 <= tc <= 8) or (tc == 19):
|
||||||
vdata = pms.adsb.velocity(msg)
|
vdata = pms.adsb.velocity(msg)
|
||||||
@@ -86,42 +85,47 @@ class Stream():
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
spd, trk, roc, tag = vdata
|
spd, trk, roc, tag = vdata
|
||||||
if tag != 'GS':
|
if tag != "GS":
|
||||||
continue
|
continue
|
||||||
if (spd is None) or (trk is None):
|
if (spd is None) or (trk is None):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
self.acs[icao]['gs'] = spd
|
self.acs[icao]["gs"] = spd
|
||||||
self.acs[icao]['trk'] = trk
|
self.acs[icao]["trk"] = trk
|
||||||
self.acs[icao]['roc'] = roc
|
self.acs[icao]["roc"] = roc
|
||||||
self.acs[icao]['tv'] = t
|
self.acs[icao]["tv"] = t
|
||||||
|
|
||||||
output_buffer.append([t, icao, 'gs', spd])
|
output_buffer.append([t, icao, "gs", spd])
|
||||||
output_buffer.append([t, icao, 'trk', trk])
|
output_buffer.append([t, icao, "trk", trk])
|
||||||
output_buffer.append([t, icao, 'roc', roc])
|
output_buffer.append([t, icao, "roc", roc])
|
||||||
|
|
||||||
|
if 5 <= tc <= 18:
|
||||||
if (5 <= tc <= 18):
|
|
||||||
oe = pms.adsb.oe_flag(msg)
|
oe = pms.adsb.oe_flag(msg)
|
||||||
self.acs[icao][oe] = msg
|
self.acs[icao][oe] = msg
|
||||||
self.acs[icao]['t'+str(oe)] = t
|
self.acs[icao]["t" + str(oe)] = t
|
||||||
|
|
||||||
if ('tpos' in self.acs[icao]) and (t - self.acs[icao]['tpos'] < 180):
|
if ("tpos" in self.acs[icao]) and (
|
||||||
|
t - self.acs[icao]["tpos"] < 180
|
||||||
|
):
|
||||||
# use single message decoding
|
# use single message decoding
|
||||||
rlat = self.acs[icao]['lat']
|
rlat = self.acs[icao]["lat"]
|
||||||
rlon = self.acs[icao]['lon']
|
rlon = self.acs[icao]["lon"]
|
||||||
latlon = pms.adsb.position_with_ref(msg, rlat, rlon)
|
latlon = pms.adsb.position_with_ref(msg, rlat, rlon)
|
||||||
elif ('t0' in self.acs[icao]) and ('t1' in self.acs[icao]) and \
|
elif (
|
||||||
(abs(self.acs[icao]['t0'] - self.acs[icao]['t1']) < 10):
|
("t0" in self.acs[icao])
|
||||||
|
and ("t1" in self.acs[icao])
|
||||||
|
and (abs(self.acs[icao]["t0"] - self.acs[icao]["t1"]) < 10)
|
||||||
|
):
|
||||||
# use multi message decoding
|
# use multi message decoding
|
||||||
try:
|
try:
|
||||||
latlon = pms.adsb.position(
|
latlon = pms.adsb.position(
|
||||||
self.acs[icao][0],
|
self.acs[icao][0],
|
||||||
self.acs[icao][1],
|
self.acs[icao][1],
|
||||||
self.acs[icao]['t0'],
|
self.acs[icao]["t0"],
|
||||||
self.acs[icao]['t1'],
|
self.acs[icao]["t1"],
|
||||||
self.lat0, self.lon0
|
self.lat0,
|
||||||
)
|
self.lon0,
|
||||||
|
)
|
||||||
except:
|
except:
|
||||||
# mix of surface and airborne position message
|
# mix of surface and airborne position message
|
||||||
continue
|
continue
|
||||||
@@ -129,16 +133,16 @@ class Stream():
|
|||||||
latlon = None
|
latlon = None
|
||||||
|
|
||||||
if latlon is not None:
|
if latlon is not None:
|
||||||
self.acs[icao]['tpos'] = t
|
self.acs[icao]["tpos"] = t
|
||||||
self.acs[icao]['lat'] = latlon[0]
|
self.acs[icao]["lat"] = latlon[0]
|
||||||
self.acs[icao]['lon'] = latlon[1]
|
self.acs[icao]["lon"] = latlon[1]
|
||||||
|
|
||||||
alt = pms.adsb.altitude(msg)
|
alt = pms.adsb.altitude(msg)
|
||||||
self.acs[icao]['alt'] = alt
|
self.acs[icao]["alt"] = alt
|
||||||
|
|
||||||
output_buffer.append([t, icao, 'lat', latlon[0]])
|
output_buffer.append([t, icao, "lat", latlon[0]])
|
||||||
output_buffer.append([t, icao, 'lon', latlon[1]])
|
output_buffer.append([t, icao, "lon", latlon[1]])
|
||||||
output_buffer.append([t, icao, 'alt', alt])
|
output_buffer.append([t, icao, "alt", alt])
|
||||||
|
|
||||||
local_updated_acs_buffer.append(icao)
|
local_updated_acs_buffer.append(icao)
|
||||||
|
|
||||||
@@ -146,35 +150,42 @@ class Stream():
|
|||||||
ac = self.acs[icao]
|
ac = self.acs[icao]
|
||||||
|
|
||||||
if 9 <= tc <= 18:
|
if 9 <= tc <= 18:
|
||||||
ac['nic_bc'] = pms.adsb.nic_b(msg)
|
ac["nic_bc"] = pms.adsb.nic_b(msg)
|
||||||
|
|
||||||
if (5 <= tc <= 8) or (9 <= tc <= 18) or (20 <= tc <= 22):
|
if (5 <= tc <= 8) or (9 <= tc <= 18) or (20 <= tc <= 22):
|
||||||
ac['HPL'], ac['RCu'], ac['RCv'] = pms.adsb.nuc_p(msg)
|
ac["HPL"], ac["RCu"], ac["RCv"] = pms.adsb.nuc_p(msg)
|
||||||
|
|
||||||
if (ac['ver'] == 1) and ('nic_s' in ac.keys()):
|
if (ac["ver"] == 1) and ("nic_s" in ac.keys()):
|
||||||
ac['Rc'], ac['VPL'] = pms.adsb.nic_v1(msg, ac['nic_s'])
|
ac["Rc"], ac["VPL"] = pms.adsb.nic_v1(msg, ac["nic_s"])
|
||||||
elif (ac['ver'] == 2) and ('nic_a' in ac.keys()) and ('nic_bc' in ac.keys()):
|
elif (
|
||||||
ac['Rc'] = pms.adsb.nic_v2(msg, ac['nic_a'], ac['nic_bc'])
|
(ac["ver"] == 2)
|
||||||
|
and ("nic_a" in ac.keys())
|
||||||
|
and ("nic_bc" in ac.keys())
|
||||||
|
):
|
||||||
|
ac["Rc"] = pms.adsb.nic_v2(msg, ac["nic_a"], ac["nic_bc"])
|
||||||
|
|
||||||
if tc == 19:
|
if tc == 19:
|
||||||
ac['HVE'], ac['VVE'] = pms.adsb.nuc_v(msg)
|
ac["HVE"], ac["VVE"] = pms.adsb.nuc_v(msg)
|
||||||
if ac['ver'] in [1, 2]:
|
if ac["ver"] in [1, 2]:
|
||||||
ac['HFOMr'], ac['VFOMr'] = pms.adsb.nac_v(msg)
|
ac["HFOMr"], ac["VFOMr"] = pms.adsb.nac_v(msg)
|
||||||
|
|
||||||
if tc == 29:
|
if tc == 29:
|
||||||
ac['PE_RCu'], ac['PE_VPL'], ac['base'] = pms.adsb.sil(msg, ac['ver'])
|
ac["PE_RCu"], ac["PE_VPL"], ac["base"] = pms.adsb.sil(
|
||||||
ac['EPU'], ac['VEPU'] = pms.adsb.nac_p(msg)
|
msg, ac["ver"]
|
||||||
|
)
|
||||||
|
ac["EPU"], ac["VEPU"] = pms.adsb.nac_p(msg)
|
||||||
|
|
||||||
if tc == 31:
|
if tc == 31:
|
||||||
ac['ver'] = pms.adsb.version(msg)
|
ac["ver"] = pms.adsb.version(msg)
|
||||||
ac['EPU'], ac['VEPU'] = pms.adsb.nac_p(msg)
|
ac["EPU"], ac["VEPU"] = pms.adsb.nac_p(msg)
|
||||||
ac['PE_RCu'], ac['PE_VPL'], ac['sil_base'] = pms.adsb.sil(msg, ac['ver'])
|
ac["PE_RCu"], ac["PE_VPL"], ac["sil_base"] = pms.adsb.sil(
|
||||||
|
msg, ac["ver"]
|
||||||
if ac['ver'] == 1:
|
)
|
||||||
ac['nic_s'] = pms.adsb.nic_s(msg)
|
|
||||||
elif ac['ver'] == 2:
|
|
||||||
ac['nic_a'], ac['nic_bc'] = pms.adsb.nic_a_c(msg)
|
|
||||||
|
|
||||||
|
if ac["ver"] == 1:
|
||||||
|
ac["nic_s"] = pms.adsb.nic_s(msg)
|
||||||
|
elif ac["ver"] == 2:
|
||||||
|
ac["nic_a"], ac["nic_bc"] = pms.adsb.nic_a_c(msg)
|
||||||
|
|
||||||
# process commb message
|
# process commb message
|
||||||
for t, msg in zip(commb_ts, commb_msgs):
|
for t, msg in zip(commb_ts, commb_msgs):
|
||||||
@@ -183,32 +194,34 @@ class Stream():
|
|||||||
if icao not in self.acs:
|
if icao not in self.acs:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
self.acs[icao]["live"] = int(t)
|
||||||
|
|
||||||
bds = pms.bds.infer(msg)
|
bds = pms.bds.infer(msg)
|
||||||
|
|
||||||
if bds == 'BDS50':
|
if bds == "BDS50":
|
||||||
roll50 = pms.commb.roll50(msg)
|
roll50 = pms.commb.roll50(msg)
|
||||||
trk50 = pms.commb.trk50(msg)
|
trk50 = pms.commb.trk50(msg)
|
||||||
rtrk50 = pms.commb.rtrk50(msg)
|
rtrk50 = pms.commb.rtrk50(msg)
|
||||||
gs50 = pms.commb.gs50(msg)
|
gs50 = pms.commb.gs50(msg)
|
||||||
tas50 = pms.commb.tas50(msg)
|
tas50 = pms.commb.tas50(msg)
|
||||||
|
|
||||||
self.acs[icao]['t50'] = t
|
self.acs[icao]["t50"] = t
|
||||||
if tas50:
|
if tas50:
|
||||||
self.acs[icao]['tas'] = tas50
|
self.acs[icao]["tas"] = tas50
|
||||||
output_buffer.append([t, icao, 'tas50', tas50])
|
output_buffer.append([t, icao, "tas50", tas50])
|
||||||
if roll50:
|
if roll50:
|
||||||
self.acs[icao]['roll'] = roll50
|
self.acs[icao]["roll"] = roll50
|
||||||
output_buffer.append([t, icao, 'roll50', roll50])
|
output_buffer.append([t, icao, "roll50", roll50])
|
||||||
if rtrk50:
|
if rtrk50:
|
||||||
self.acs[icao]['rtrk'] = rtrk50
|
self.acs[icao]["rtrk"] = rtrk50
|
||||||
output_buffer.append([t, icao, 'rtrk50', rtrk50])
|
output_buffer.append([t, icao, "rtrk50", rtrk50])
|
||||||
|
|
||||||
if trk50:
|
if trk50:
|
||||||
output_buffer.append([t, icao, 'trk50', trk50])
|
output_buffer.append([t, icao, "trk50", trk50])
|
||||||
if gs50:
|
if gs50:
|
||||||
output_buffer.append([t, icao, 'gs50', gs50])
|
output_buffer.append([t, icao, "gs50", gs50])
|
||||||
|
|
||||||
elif bds == 'BDS60':
|
elif bds == "BDS60":
|
||||||
ias60 = pms.commb.ias60(msg)
|
ias60 = pms.commb.ias60(msg)
|
||||||
hdg60 = pms.commb.hdg60(msg)
|
hdg60 = pms.commb.hdg60(msg)
|
||||||
mach60 = pms.commb.mach60(msg)
|
mach60 = pms.commb.mach60(msg)
|
||||||
@@ -216,28 +229,28 @@ class Stream():
|
|||||||
roc60ins = pms.commb.vr60ins(msg)
|
roc60ins = pms.commb.vr60ins(msg)
|
||||||
|
|
||||||
if ias60 or hdg60 or mach60:
|
if ias60 or hdg60 or mach60:
|
||||||
self.acs[icao]['t60'] = t
|
self.acs[icao]["t60"] = t
|
||||||
if ias60:
|
if ias60:
|
||||||
self.acs[icao]['ias'] = ias60
|
self.acs[icao]["ias"] = ias60
|
||||||
if hdg60:
|
if hdg60:
|
||||||
self.acs[icao]['hdg'] = hdg60
|
self.acs[icao]["hdg"] = hdg60
|
||||||
if mach60:
|
if mach60:
|
||||||
self.acs[icao]['mach'] = mach60
|
self.acs[icao]["mach"] = mach60
|
||||||
|
|
||||||
if roc60baro:
|
if roc60baro:
|
||||||
output_buffer.append([t, icao, 'roc60baro', roc60baro])
|
output_buffer.append([t, icao, "roc60baro", roc60baro])
|
||||||
if roc60ins:
|
if roc60ins:
|
||||||
output_buffer.append([t, icao, 'roc60ins', roc60ins])
|
output_buffer.append([t, icao, "roc60ins", roc60ins])
|
||||||
|
|
||||||
# clear up old data
|
# clear up old data
|
||||||
for icao in list(self.acs.keys()):
|
for icao in list(self.acs.keys()):
|
||||||
if self.t - self.acs[icao]['live'] > self.cache_timeout:
|
if self.t - self.acs[icao]["live"] > self.cache_timeout:
|
||||||
del self.acs[icao]
|
del self.acs[icao]
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if self.dumpto is not None:
|
if self.dumpto is not None:
|
||||||
dh = str(datetime.datetime.now().strftime("%Y%m%d_%H"))
|
dh = str(datetime.datetime.now().strftime("%Y%m%d_%H"))
|
||||||
fn = self.dumpto + '/pymodes_dump_%s.csv' % dh
|
fn = self.dumpto + "/pymodes_dump_%s.csv" % dh
|
||||||
output_buffer.sort(key=lambda x: x[0])
|
output_buffer.sort(key=lambda x: x[0])
|
||||||
with open(fn, "a") as f:
|
with open(fn, "a") as f:
|
||||||
writer = csv.writer(f)
|
writer = csv.writer(f)
|
||||||
@@ -248,8 +261,4 @@ class Stream():
|
|||||||
def get_aircraft(self):
|
def get_aircraft(self):
|
||||||
"""all aircraft that are stored in memeory"""
|
"""all aircraft that are stored in memeory"""
|
||||||
acs = self.acs
|
acs = self.acs
|
||||||
icaos = list(acs.keys())
|
|
||||||
for icao in icaos:
|
|
||||||
if acs[icao]['lat'] is None:
|
|
||||||
acs.pop(icao)
|
|
||||||
return acs
|
return acs
|
||||||
|
|||||||
Reference in New Issue
Block a user