openwebrx/owrx/adsb/modes.py

95 lines
3.3 KiB
Python
Raw Normal View History

2023-08-23 00:40:24 +02:00
from csdr.module import PickleModule
from math import sqrt, atan2, pi
import logging
logger = logging.getLogger(__name__)
FEET_PER_METER = 3.28084
class ModeSParser(PickleModule):
def process(self, input):
format = (input[0] & 0b11111000) >> 3
2023-08-23 13:48:58 +02:00
message = {
2023-08-23 00:40:24 +02:00
"mode": "ADSB",
"format": format
}
if format == 17:
message["capability"] = input[0] & 0b111
message["icao"] = input[1:4].hex()
type = (input[4] & 0b11111000) >> 3
message["type"] = type
if type in range(1, 5):
# identification message
id = [
(input[5] & 0b11111100) >> 2,
((input[5] & 0b00000011) << 4) | ((input[6] & 0b11110000) >> 4),
((input[6] & 0b00001111) << 2) | ((input[7] & 0b11000000) >> 6),
input[7] & 0b00111111,
(input[8] & 0b11111100) >> 2,
((input[8] & 0b00000011) << 4) | ((input[9] & 0b11110000) >> 4),
((input[9] & 0b00001111) << 2) | ((input[10] & 0b11000000) >> 6),
input[10] & 0b00111111
]
message["identification"] = bytes(b + (0x40 if b < 27 else 0) for b in id).decode("ascii")
elif type in range(5, 9):
# surface position
pass
elif type in range(9, 19):
# airborne position (w/ baro altitude)
q = (input[5] & 0b1)
2023-08-23 13:48:58 +02:00
altitude = ((input[5] & 0b11111110) << 3) | ((input[6] & 0b11110000) >> 4)
2023-08-23 00:40:24 +02:00
if q:
message["altitude"] = altitude * 25 - 1000
else:
# TODO: it's gray encoded
message["altitude"] = altitude * 100
elif type == 19:
# airborne velocity
subtype = input[4] & 0b111
if subtype in range(1, 3):
dew = (input[5] & 0b00000100) >> 2
vew = ((input[5] & 0b00000011) << 8) | input[6]
dns = (input[7] & 0b10000000) >> 7
vns = ((input[7] & 0b01111111) << 3) | ((input[8] & 0b1110000000) >> 5)
vx = vew - 1
if dew:
vx *= -1
vy = vns - 1
if dns:
vy *= -1
# supersonic
if subtype == 2:
vx *= 4
vy *= 4
message["groundspeed"] = sqrt(vx ** 2 + vy ** 2)
message["groundtrack"] = (atan2(vx, vy) * 360 / (2 * pi)) % 360
else:
logger.debug("subtype: %i", subtype)
elif type in range(20, 23):
# airborne position (w/GNSS height)
altitude = (input[5] << 4) | ((input[6] & 0b1111) >> 4)
message["altitude"] = altitude * FEET_PER_METER
elif type == 28:
# aircraft status
pass
elif type == 29:
# target state and status information
pass
elif type == 31:
# aircraft operation status
pass
return message