Skip to content

Commit

Permalink
split out logs by message type, try some regex building blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
rpatel3001 committed Feb 29, 2024
1 parent 716c0d4 commit 1eec700
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 74 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Under active development, everything is subject to change without notice.
|----------|-------------|---------|
| `JSON_IN` | Semi-colon separated list of `host:port` entries to connect to for JSON ingest. | acars_router:15550 |
| `SBS_OUT` | Semi-colon separated list of `host:port` entries to connect to for SBS/Basestation output. | ultrafeeder:12000 |
| `LOG_FILE` | Set to any value to message text, type, SBS output, and adsbexchange link to a file in `/log`. | Unset |
| `LOG_FILE` | Set to any value to message text, type, SBS output, and adsbexchange link to files in `/log`. | Unset |

## Docker Compose

Expand Down
65 changes: 28 additions & 37 deletions rootfs/scripts/acars2pos.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,8 @@ def thread_wrapper(func, *args):
txqs.append(SimpleQueue())
Thread(name=f"tx {s[0]}:{s[1]}", target=thread_wrapper, args=(tx_thread, s, txqs[-1])).start()

if not os.path.exists("/log"):
if getenv("LOG_FILE") and not os.path.exists("/log"):
os.makedirs("/log")
logfile = open(f"/log/{datetime.now(timezone.utc):%Y_%m_%d}.log", "a", 1)
logfileh1 = open(f"/log/{datetime.now(timezone.utc):%Y_%m_%d}.h1.log", "a", 1)

while True:
try:
Expand All @@ -99,6 +97,31 @@ def thread_wrapper(func, *args):
if not sbs.get("txt") and not sbs.get("lat"):
continue

if not sbs.get("reg"):
sbs["reg"] = icao2reg(sbs.get("icao", ""))

sbs["reg"] = sub(r'[^a-zA-Z0-9-]', '', sbs["reg"]).upper()

if not sbs.get("icao"):
sbs["icao"] = reg2icao(sbs.get("reg", ""))
if not sbs.get("icao"):
print(f'{Fore.GREEN}xxxxxxx {sbs["reg"]}{Fore.RESET}', file=stderr)
continue

if sbs["type"] == "acars":
squawk = "1111"
elif sbs["type"] == "vdlm2":
squawk = "2222"
elif sbs["type"] == "hfdl":
squawk = "3333"
else:
squawk = "0000"

if getenv("LOG_FILE") and sbs.get("msgtype") and sbs.get("type") != "hfdl":
with open(f"/log/{sbs.get('msgtype')}.log", "a", 1) as logfile:
logfile.write(f'{sbs["type"]}\t{sbs.get("msgtype")}\thttps://globe.adsbexchange.com/?icao={sbs["icao"]}&showTrace={datetime.fromtimestamp(sbs["time"], tz=timezone.utc):%Y-%m-%d}&timestamp={sbs["time"]}\n')
logfile.write(f'{sbs["txt"]}\n\n')

if sbs.get("lat"):
lat = sbs["lat"]
lon = sbs["lon"]
Expand Down Expand Up @@ -169,8 +192,8 @@ def thread_wrapper(func, *args):
else:
continue
elif len(pos2a) and len(pos2b):
txt = sub(r'(LAT)', Fore.MAGENTA + r'\1' + Fore.RESET, sbs["txt"])
txt = sub(r'(LON)', Fore.MAGENTA + r'\1' + Fore.RESET, txt)
txt = sub(r'(LAT)', Fore.RED + r'\1' + Fore.RESET, sbs["txt"])
txt = sub(r'(LON)', Fore.RED + r'\1' + Fore.RESET, txt)
print(f"old regex 3 matched message type {sbs['msgtype']}")
print(txt)
continue
Expand All @@ -180,43 +203,11 @@ def thread_wrapper(func, *args):
print(f'{sbs["type"]} {sbs.get("msgtype")}', file=stderr)
# print(pos, file=stderr)

if not sbs.get("reg"):
sbs["reg"] = icao2reg(sbs.get("icao", ""))

sbs["reg"] = sub(r'[^a-zA-Z0-9-]', '', sbs["reg"]).upper()

if not sbs.get("icao"):
sbs["icao"] = reg2icao(sbs.get("reg", ""))
if not sbs.get("icao"):
print(f'{Fore.GREEN}xxxxxxx {sbs["reg"]}{Fore.RESET}', file=stderr)
continue

if sbs["type"] == "acars":
squawk = "1111"
elif sbs["type"] == "vdlm2":
squawk = "2222"
elif sbs["type"] == "hfdl":
squawk = "3333"
else:
squawk = "0000"

out = f'MSG,3,1,1,{sbs["icao"].upper()},1,{datetime.fromtimestamp(sbs["time"], tz=timezone.utc):%Y/%m/%d,%T},{datetime.now(timezone.utc):%Y/%m/%d,%T},{sbs.get("flight", "")},,,,{lat:.3f},{lon:.3f},,{squawk},,,,'

print(f'https://globe.adsbexchange.com/?icao={sbs["icao"]}&showTrace={datetime.fromtimestamp(sbs["time"], tz=timezone.utc):%Y-%m-%d}&timestamp={sbs["time"]}')
print(f'{Fore.BLUE}{out}{Fore.RESET}\n', file=stderr)

if getenv("LOG_FILE") and sbs.get("msgtype") and sbs.get("type") != "hfdl":
if sbs["msgtype"] == "H1":
logfileh1.write(f'{sbs["txt"]}\n')
logfileh1.write(f'{sbs["type"]} {sbs.get("msgtype")}\n')
logfileh1.write(out+"\n")
logfileh1.write(f'https://globe.adsbexchange.com/?icao={sbs["icao"]}&showTrace={datetime.fromtimestamp(sbs["time"], tz=timezone.utc):%Y-%m-%d}&timestamp={sbs["time"]}\n\n')
else:
logfile.write(f'{sbs["txt"]}\n')
logfile.write(f'{sbs["type"]} {sbs.get("msgtype")}\n')
logfile.write(out+"\n")
logfile.write(f'https://globe.adsbexchange.com/?icao={sbs["icao"]}&showTrace={datetime.fromtimestamp(sbs["time"], tz=timezone.utc):%Y-%m-%d}&timestamp={sbs["time"]}\n\n')

for q in txqs:
q.put(out+"\r\n")
except BaseException:
Expand Down
116 changes: 80 additions & 36 deletions rootfs/scripts/acars_decode/Decoder.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,55 @@
from re import compile, sub
from colorama import Fore

rgxs = [compile(r"([NS])[ 0]{0,2}(\d{1,2}\.\d{3}).?([WE])[0 ]{0,2}(\d{1,3}\.\d{3})"),
compile(r"([NS])[ 0]{0,1}(\d{1,2})[ 0]{0,1}(\d{1,2}\.\d{1}).?([WE])[ 0]{0,2}(\d{1,3}?)[ 0]{0,1}(\d{1,2}\.\d{1})"),
compile(r"([NS])[ 0]{0,1}(\d{1,2})[ 0]{0,3}(\d{0,2}\.\d{2}).?([WE])[ 0]{0,2}(\d{1,3})[ 0]{0,1}(\d{1,2}\.\d{2})"),
compile(r"([NS])\s?(\d{2})(\d{2})(\d{2}).?([WE])\s?(\d{2,3})(\d{2})(\d{2})"),
compile(r"([NS])[ 0]?([ 0\d]\d)(\d{3}).?([WE])([ 0\d][ 0\d]\d)(\d{3})"),
compile(r"[0 ]{0,1}(\d{1,2})[0 ]{0,1}(\d{1,2}\.\d{1})([NS])[ 0]{0,2}(\d{1,3})[0 ]{0,1}(\d{1,2}\.\d{1})([WE])"),
compile(r"[ 0]{0,1}(\d{1,2})[ 0]{0,1}(\d{1,2})([NS])[ 0]{0,2}(\d{1,3})[ 0]{0,1}(\d{1,2})([WE])"),
compile(r"LAT ([NS]) [0 ]{0,1}(\d{1,2}):(\d{2}\.\d{1}) LONG ([WE]) [0 ]{0,1}(\d{1,2}):(\d{2}\.\d{1})")]

dlat = r"(?P<dlat>[NS])"
dlon = r"(?P<dlon>[WE])"

spdig2 = r"(?:\s|\d)\d"
spdig3 = r"(?:\s\s|\s\d|\d\d)\d"

dig1 = r"\d"
dig2 = r"\d\d"
dig3 = r"\d\d\d"


def name(n, rgx):
return f"(?P<{n}>{rgx})"

def sd2(n):
return name(n, spdig2)

def sd3(n):
return name(n, spdig3)

def d1(n):
return name(n, dig1)

def d2(n):
return name(n, dig2)

def d3(n):
return name(n, dig3)


rgxs = [
compile(dlat + r"[ 0]{0,2}(\d{1,2}\.\d{3}).?" + dlon + r"[ 0]{0,2}(\d{1,3}\.\d{3})"), # thousandths of degrees
compile(dlat + r"[ 0]{0,1}(\d{1,2})[ 0]{0,1}(\d{1,2}\.\d{1}).?" + dlon + r"[ 0]{0,2}(\d{1,3}?)[ 0]{0,1}(\d{1,2}\.\d{1})"), # tenths of minutes
compile(dlat + r"[ 0]{0,1}(\d{1,2})[ 0]{0,3}(\d{0,2}\.\d{2}).?" + dlon +r"[ 0]{0,2}(\d{1,3})[ 0]{0,1}(\d{1,2}\.\d{2})"), # hundredths of minutes
compile(dlat + r"\s?(\d{2})(\d{2})(\d{2}).?" + dlon + r"\s?(\d{2,3})(\d{2})(\d{2})"), # seconds
compile(dlat + r"[ 0]?([ 0\d]\d)(\d{3}).?" + dlon + r"([ 0\d][ 0\d]\d)(\d{3})"), # tenths of minutes, no decimal
compile(r"[ 0]{0,1}(\d{1,2})[ 0]{0,1}(\d{1,2}\.\d{1})" + dlat + r"[ 0]{0,2}(\d{1,3})[ 0]{0,1}(\d{1,2}\.\d{1})" + dlon), # tenths of minutes, direction after
compile(r"[ 0]{0,1}(\d{1,2})[ 0]{0,1}(\d{1,2})" + dlat + r"[ 0]{0,2}(\d{1,3})[ 0]{0,1}(\d{1,2})" + dlon), # minutes, direction after
compile(r"LAT " + dlat + r" [ 0]{0,1}(\d{1,2}):(\d{2}\.\d{1}) LONG " + dlon + r" [ 0]{0,1}(\d{1,2}):(\d{2}\.\d{1})"), # tenths of minuts, colon separator
]

msgrgx = {
"10": [compile(dlat + " " + sd2("latdeg") + "\." + d3("latdeg1000") + "\/" + dlon + sd3("londeg") + "\." + d3("londeg1000"))],
"14": [compile(dlat + sd2("latdeg") + d2("latmin") + d1("latmin10") + dlon + sd3("londeg") + d2("lonmin") + d1("lonmin10"))],
"15": [compile(dlat + sd2("latdeg") + d2("latmin") + d1("latmin10") + dlon + sd3("londeg") + d2("lonmin") + d1("lonmin10")),
compile(dlat + sd2("latdeg") + d2("latmin") + d2("latsec") + dlon + sd3("londeg") + d2("lonmin") + d2("lonsec"))],
"4T": [compile(d2("latdeg") + d2("latmin") + r"\." + d1("latmin10") + dlat + d3("londeg") + d2("lonmin") + r"\." + d1("lonmin10") + dlon)],
}

def decode(msg):
if msg.get("vdl2"):
Expand All @@ -21,39 +62,42 @@ def decode(msg):
if not dat:
return None

if dat.get("msgtype") == "4N":
rgx = compile(r"([NS])(\d{3})(\d{3}) ([WE])(\d{3})(\d{3})")
raw = rgx.findall(dat["txt"])
if len(raw) == 1:
pos = dat["txt"]
for pat in raw[0]:
pos = sub(f"({pat})", Fore.GREEN + r"\1" + Fore.RESET, pos)
print(f"matched message type {dat['msgtype']}")
print(pos)
raw = rgx.search(dat["txt"])
dat["lat"] = (int(raw.group(2)) + int(raw.group(3))/600) * (-1 if raw.group(1) == "S" else 1)
dat["lon"] = (int(raw.group(5)) + int(raw.group(6))/600) * (-1 if raw.group(4) == "W" else 1)
elif dat.get("msgtype") == "4T":
rgx = compile(r"(\d{2})(\d{2}\.\d{1})([NS])[ 0](\d{2})(\d{2}\.\d{1})([WE])")
raw = rgx.findall(dat["txt"])
if len(raw) == 1:
pos = dat["txt"]
for pat in raw[0]:
pos = sub(f"({pat})", Fore.GREEN + r"\1" + Fore.RESET, pos)
print(f"matched message type {dat['msgtype']}")
print(pos)
raw = rgx.search(dat["txt"])
dat["lat"] = (int(raw.group(1)) + float(raw.group(2))/60) * (-1 if raw.group(3) == "S" else 1)
dat["lon"] = (int(raw.group(4)) + float(raw.group(5))/60) * (-1 if raw.group(6) == "W" else 1)
dat["txt"] = dat.get("txt", "").upper().replace("\r", "").replace("\n", "")

rgxl = msgrgx.get(dat.get("msgtype"))
if rgxl and dat.get("msgtype"):
for rgx in rgxl:
raw = rgx.findall(dat["txt"])
if len(raw) == 1:
pos = rgx.sub(Fore.GREEN + r"\g<0>" + Fore.RESET, dat["txt"])
print(f"matched message type {dat['msgtype']}")
print(pos)
raw = rgx.search(dat["txt"]).groupdict()
print(raw)
dat["lat"] = float(raw.get("latdeg", 0))
dat["lat"] += float(raw.get("lat1000", 0))/1000
dat["lat"] += float(raw.get("latmin", 0))/60
dat["lat"] += float(raw.get("latmin10", 0))/600
dat["lat"] += float(raw.get("latmin100", 0))/6000
dat["lat"] += float(raw.get("latsec", 0))/3600
dat["lat"] *= -1 if raw.get("dlat") == "S" else 1

dat["lon"] = float(raw.get("londeg", 0))
dat["lon"] += float(raw.get("lon1000", 0))/1000
dat["lon"] += float(raw.get("lonmin", 0))/60
dat["lon"] += float(raw.get("lonmin10", 0))/600
dat["lon"] += float(raw.get("lonmin100", 0))/6000
dat["lon"] += float(raw.get("lonsec", 0))/3600
dat["lon"] *= -1 if raw.get("dlon") == "W" else 1

if dat.get("lat") and abs(dat["lat"]) <= 90 and abs(dat["lon"]) <= 180 :
break

if not dat.get("lat"):
dat["txt"] = dat.get("txt", "").upper().replace("\r", "").replace("\n", "")
for i,rgx in enumerate(rgxs):
raw = rgx.findall(dat["txt"])
if len(raw) == 1:
pos = dat["txt"]
for pat in raw[0]:
pos = sub(f"({pat})", Fore.RED + r"\1" + Fore.RESET, pos)
pos = rgx.sub(Fore.RED + r"\g<0>" + Fore.RESET, dat["txt"])
print(f"regex {i} matched message type {dat['msgtype']}")
print(pos)

Expand Down

0 comments on commit 1eec700

Please sign in to comment.