Files
pyModeS/pyModeS/decoder/uplink.py
T
2022-11-01 16:32:42 +09:00

224 lines
6.4 KiB
Python

from typing import Optional
from .. import common
from textwrap import wrap
def uplink_icao(msg: str) -> str:
"Calculate the ICAO address from a Mode-S interrogation (uplink message)"
p_gen = 0xFFFA0480 << ((len(msg) - 14) * 4)
data = int(msg[:-6], 16)
PA = int(msg[-6:], 16)
ad = 0
topbit = 0b1 << (len(msg) * 4 - 25)
for j in range(0, len(msg) * 4, 1):
if data & topbit:
data ^= p_gen
data = (data << 1) + ((PA >> 23) & 1)
PA = PA << 1
if j > (len(msg) * 4 - 26):
ad = ad + ((data >> (len(msg) * 4 - 25)) & 1)
ad = ad << 1
return "%06X" % (ad >> 2)
def uf(msg: str) -> int:
"""Decode Uplink Format value, bits 1 to 5."""
ufbin = common.hex2bin(msg[:2])
return min(common.bin2int(ufbin[0:5]), 24)
def bds(msg: str) -> Optional[str]:
"Decode requested BDS register from selective (Roll Call) interrogation."
UF = uf(msg)
msgbin = common.hex2bin(msg)
msgbin_split = wrap(msgbin, 8)
mbytes = list(map(common.bin2int, msgbin_split))
if UF in {4, 5, 20, 21}:
di = mbytes[1] & 0x7 # DI - Designator Identification
RR = mbytes[1] >> 3 & 0x1F
if RR > 15:
BDS1 = RR - 16
if di == 7:
RRS = mbytes[2] & 0x0F
BDS2 = RRS
elif di == 3:
RRS = ((mbytes[2] & 0x1) << 3) | ((mbytes[3] & 0xE0) >> 5)
BDS2 = RRS
else:
# for other values of DI, the BDS2 is assumed 0
# (as per ICAO Annex 10 Vol IV)
BDS2 = 0
return str(format(BDS1,"X")) + str(format(BDS2,"X"))
else:
return None
else:
return None
def pr(msg: str) -> Optional[int]:
"""Decode PR (probability of reply) field from All Call interrogation.
Interpretation:
0 signifies reply with probability of 1
1 signifies reply with probability of 1/2
2 signifies reply with probability of 1/4
3 signifies reply with probability of 1/8
4 signifies reply with probability of 1/16
5, 6, 7 not assigned
8 signifies disregard lockout, reply with probability of 1
9 signifies disregard lockout, reply with probability of 1/2
10 signifies disregard lockout, reply with probability of 1/4
11 signifies disregard lockout, reply with probability of 1/8
12 signifies disregard lockout, reply with probability of 1/16
13, 14, 15 not assigned.
"""
msgbin = common.hex2bin(msg)
msgbin_split = wrap(msgbin, 8)
mbytes = list(map(common.bin2int, msgbin_split))
if uf(msg) == 11:
return ((mbytes[0] & 0x7) << 1) | ((mbytes[1] & 0x80) >> 7)
else:
return None
def ic(msg: str) -> Optional[str]:
"""Decode IC (interrogator code) from a ground-based interrogation."""
UF = uf(msg)
msgbin = common.hex2bin(msg)
msgbin_split = wrap(msgbin, 8)
mbytes = list(map(common.bin2int, msgbin_split))
IC = None
if UF == 11:
codeLabel = mbytes[1] & 0x7
icField = (mbytes[1] >> 3) & 0xF
# Store the Interogator Code
ic_switcher = {
0: "II" + str(icField),
1: "SI" + str(icField),
2: "SI" + str(icField + 16),
3: "SI" + str(icField + 32),
4: "SI" + str(icField + 48),
}
IC = ic_switcher.get(codeLabel, "")
if UF in {4, 5, 20, 21}:
di = mbytes[1] & 0x7
RR = mbytes[1] >> 3 & 0x1F
if RR > 15:
BDS1 = RR - 16 # noqa: F841
if di == 0 or di == 1 or di == 7:
# II
II = (mbytes[2] >> 4) & 0xF
IC = "II" + str(II)
elif di == 3:
# SI
SI = (mbytes[2] >> 2) & 0x3F
IC = "SI" + str(SI)
return IC
def lockout(msg):
"""Decode the lockout command from selective (Roll Call) interrogation."""
msgbin = common.hex2bin(msg)
msgbin_split = wrap(msgbin, 8)
mbytes = list(map(common.bin2int, msgbin_split))
if uf(msg) in {4, 5, 20, 21}:
lockout = False
di = mbytes[1] & 0x7
if di == 7:
# LOS
if ((mbytes[3] & 0x40) >> 6) == 1:
lockout = True
elif di == 3:
# LSS
if ((mbytes[2] & 0x2) >> 1) == 1:
lockout = True
return lockout
else:
return None
def uplink_fields(msg):
"""Decode individual fields of a ground-based interrogation."""
msgbin = common.hex2bin(msg)
msgbin_split = wrap(msgbin, 8)
mbytes = list(map(common.bin2int, msgbin_split))
PR = ""
IC = ""
lockout = False
di = ""
RR = ""
RRS = ""
BDS = ""
if uf(msg) == 11:
# Probability of Reply decoding
PR = ((mbytes[0] & 0x7) << 1) | ((mbytes[1] & 0x80) >> 7)
# Get cl and ic bit fields from the data
# Decode the SI or II interrogator code
codeLabel = mbytes[1] & 0x7
icField = (mbytes[1] >> 3) & 0xF
# Store the Interogator Code
ic_switcher = {
0: "II" + str(icField),
1: "SI" + str(icField),
2: "SI" + str(icField + 16),
3: "SI" + str(icField + 32),
4: "SI" + str(icField + 48),
}
IC = ic_switcher.get(codeLabel, "")
if uf(msg) in {4, 5, 20, 21}:
# Decode the DI and get the lockout information conveniently
# (LSS or LOS)
# DI - Designator Identification
di = mbytes[1] & 0x7
RR = mbytes[1] >> 3 & 0x1F
if RR > 15:
BDS1 = RR - 16
BDS2 = 0
if di == 0 or di == 1:
# II
II = (mbytes[2] >> 4) & 0xF
IC = "II" + str(II)
elif di == 7:
# LOS
if ((mbytes[3] & 0x40) >> 6) == 1:
lockout = True
# II
II = (mbytes[2] >> 4) & 0xF
IC = "II" + str(II)
RRS = mbytes[2] & 0x0F
BDS2 = RRS
elif di == 3:
# LSS
if ((mbytes[2] & 0x2) >> 1) == 1:
lockout = True
# SI
SI = (mbytes[2] >> 2) & 0x3F
IC = "SI" + str(SI)
RRS = ((mbytes[2] & 0x1) << 3) | ((mbytes[3] & 0xE0) >> 5)
BDS2 = RRS
if RR > 15:
BDS = str(format(BDS1,"X")) + str(format(BDS2,"X"))
return {
"DI": di,
"IC": IC,
"LOS": lockout,
"PR": PR,
"RR": RR,
"RRS": RRS,
"BDS": BDS,
}