Skip to content

Commit c1e8ac2

Browse files
optionally use the rust parser
1 parent e1cde51 commit c1e8ac2

File tree

3 files changed

+375
-112
lines changed

3 files changed

+375
-112
lines changed

ogn/parser/parse.py

Lines changed: 126 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from datetime import datetime, timezone
22

3-
from ogn.parser.utils import createTimestamp, parseAngle, KNOTS_TO_MS, KPH_TO_MS, FEETS_TO_METER, INCH_TO_MM, fahrenheit_to_celsius, CheapRuler, normalized_quality
3+
from ogn.parser.utils import FPM_TO_MS, HPM_TO_DEGS, createTimestamp, parseAngle, KNOTS_TO_MS, KPH_TO_MS, FEETS_TO_METER, INCH_TO_MM, fahrenheit_to_celsius, CheapRuler, normalized_quality
44
from ogn.parser.pattern import PATTERN_APRS, PATTERN_APRS_POSITION, PATTERN_APRS_POSITION_WEATHER, PATTERN_APRS_STATUS, PATTERN_SERVER
55
from ogn.parser.exceptions import AprsParseError, OgnParseError
66

@@ -19,26 +19,141 @@
1919
from ogn.parser.aprs_comment.microtrak_parser import MicrotrakParser
2020
from ogn.parser.aprs_comment.generic_parser import GenericParser
2121

22+
from ogn_parser import parse as rust_parse
23+
2224
positions = {}
2325
server_timestamp = None
2426

27+
mapping = {
28+
'OGCAPT': 'capturs',
29+
'OGNFNT': 'fanet',
30+
'OGFLR': 'flarm',
31+
'OGFLR6': 'flarm',
32+
'OGFLR7': 'flarm',
33+
'OGFLYM': 'flymaster',
34+
'OGINRE': 'inreach',
35+
'OGLT24': 'lt24',
36+
'OGNMTK': 'microtrak',
37+
'OGNAVI': 'naviter',
38+
'OGNSDR': 'receiver',
39+
'OGNSKY': 'safesky',
40+
'OGPAW': 'pilot_aware',
41+
'OGSKYL': 'skylines',
42+
'OGSPID': 'spider',
43+
'OGSPOT': 'spot',
44+
'OGNTRK': 'tracker',
45+
}
46+
2547

26-
def parse(aprs_message, reference_timestamp=None, calculate_relations=False, use_server_timestamp=True):
48+
def parse(aprs_message, reference_timestamp=None, calculate_relations=False, use_server_timestamp=True, use_rust_parser=False):
2749
global server_timestamp
2850

2951
if use_server_timestamp is True:
3052
reference_timestamp = server_timestamp or datetime.now(timezone.utc)
3153
elif reference_timestamp is None:
3254
reference_timestamp = datetime.now(timezone.utc)
3355

34-
message = parse_aprs(aprs_message, reference_timestamp=reference_timestamp)
35-
if message['aprs_type'] == 'position' or message['aprs_type'] == 'status':
36-
try:
37-
message.update(parse_comment(message['comment'],
38-
dstcall=message['dstcall'],
39-
aprs_type=message['aprs_type']))
40-
except Exception:
41-
raise OgnParseError(f"dstcall: {message['dstcall']}, aprs_type: {message['aprs_type']}, comment: {message['comment']}")
56+
if use_rust_parser:
57+
rust_zeug = rust_parse(aprs_message)
58+
message = {'raw_message': aprs_message, 'reference_timestamp': reference_timestamp}
59+
if parser_error := rust_zeug.get('parsererror'):
60+
message['aprs_type'] = 'comment'
61+
message['comment'] = str(parser_error)
62+
elif aprs_packet := rust_zeug.get('aprspacket'):
63+
message.update({
64+
'aprs_type': 'position',
65+
'beacon_type': mapping.get(aprs_packet['to'], 'unknown'),
66+
'name': aprs_packet['from'],
67+
'dstcall': aprs_packet['to'],
68+
})
69+
if via := aprs_packet.get('via'):
70+
message['receiver_name'] = via[-1]
71+
if aprs_packet['via'][0] != 'TCPIP*' and aprs_packet['via'][0].endswith('*'): message['relay'] = aprs_packet['via'][0][:-1]
72+
if position := aprs_packet.get('position'):
73+
message.update({
74+
'latitude': position['latitude'],
75+
'longitude': position['longitude'],
76+
'symboltable': position['symbol_table'],
77+
'symbolcode': position['symbol_code'],
78+
})
79+
if 'timestamp' in position: message['timestamp'] = createTimestamp(position['timestamp'], reference_timestamp)
80+
81+
if 'wind_direction' in position:
82+
message['aprs_type'] = 'position_weather'
83+
if 'wind_direction' in position: message["wind_direction"] = position['wind_direction']
84+
if 'wind_speed' in position: message["wind_speed"] = position['wind_speed'] * KNOTS_TO_MS / KPH_TO_MS
85+
if 'gust' in position: message['wind_speed_peak'] = position['gust'] * KNOTS_TO_MS / KPH_TO_MS
86+
if 'temperature' in position: message['temperature'] = fahrenheit_to_celsius(position['temperature'])
87+
if 'rainfall_1h' in position: message['rainfall_1h'] = position['rainfall_1h'] / 100.0 * INCH_TO_MM
88+
if 'rainfall_24h' in position: message['rainfall_24h'] = position['rainfall_24h'] / 100.0 * INCH_TO_MM
89+
if 'humidity' in position: message['humidity'] = 1. if position['humidity'] == 0 else position['humidity'] * 0.01
90+
if 'barometric_pressure' in position: message['barometric_pressure'] = position['barometric_pressure']
91+
92+
if 'course' in position: message["track"] = position['course']
93+
if 'speed' in position: message["ground_speed"] = position['speed'] * KNOTS_TO_MS / KPH_TO_MS
94+
if 'altitude' in position: message["altitude"] = position['altitude'] * FEETS_TO_METER
95+
96+
if 'reserved' in position: message['reserved'] = position['reserved']
97+
if 'address_type' in position: message['address_type'] = position['address_type']
98+
if 'aircraft_type' in position: message['aircraft_type'] = position['aircraft_type']
99+
if 'is_notrack' in position: message['no-tracking'] = position['is_notrack']
100+
if 'is_stealth' in position: message['stealth'] = position['is_stealth']
101+
if 'address' in position: message['address'] = f"{position['address']:06X}"
102+
103+
if 'climb_rate' in position: message["climb_rate"] = position['climb_rate'] * FPM_TO_MS
104+
if 'turn_rate' in position: message["turn_rate"] = position['turn_rate'] * HPM_TO_DEGS
105+
if 'signal_quality' in position: message["signal_quality"] = position['signal_quality']
106+
if 'error' in position: message["error_count"] = position['error']
107+
if 'frequency_offset' in position: message["frequency_offset"] = position['frequency_offset']
108+
if 'gps_quality' in position: message["gps_quality"] = position['gps_quality']
109+
if 'flight_level' in position: message["flightlevel"] = position['flight_level']
110+
if 'signal_power' in position: message["signal_power"] = position['signal_power']
111+
if 'software_version' in position: message["software_version"] = position['software_version']
112+
if 'hardware_version' in position: message["hardware_version"] = position['hardware_version']
113+
if 'original_address' in position: message["real_address"] = f"{position['original_address']:06X}"
114+
115+
if 'unparsed' in position: message["user_comment"] = position['unparsed']
116+
117+
elif status := aprs_packet.get('status'):
118+
message['aprs_type'] = 'status'
119+
if 'timestamp' in status: message['timestamp'] = createTimestamp(status['timestamp'], reference_timestamp)
120+
121+
if 'version' in status: message["version"] = status['version']
122+
if 'platform' in status: message["platform"] = status['platform']
123+
if 'cpu_load' in status: message["cpu_load"] = status['cpu_load']
124+
if 'ram_free' in status: message["free_ram"] = status['ram_free']
125+
if 'ram_total' in status: message["total_ram"] = status['ram_total']
126+
if 'ntp_offset' in status: message["ntp_error"] = status['ntp_offset']
127+
if 'ntp_correction' in status: message["rt_crystal_correction"] = status['ntp_correction']
128+
if 'voltage' in status: message["voltage"] = status['voltage']
129+
if 'amperage' in status: message["amperage"] = status['amperage']
130+
if 'cpu_temperature' in status: message["cpu_temp"] = status['cpu_temperature']
131+
if 'visible_senders' in status: message["senders_visible"] = status['visible_senders']
132+
if 'latency' in status: message["latency"] = status['latency']
133+
if 'senders' in status: message["senders_total"] = status['senders']
134+
if 'rf_correction_manual' in status: message["rec_crystal_correction"] = status['rf_correction_manual']
135+
if 'rf_correction_automatic' in status: message["rec_crystal_correction_fine"] = status['rf_correction_automatic']
136+
if 'noise' in status: message["rec_input_noise"] = status['noise']
137+
if 'senders_signal_quality' in status: message["senders_signal"] = status['senders_signal_quality']
138+
if 'senders_messages' in status: message["senders_messages"] = status['senders_messages']
139+
if 'good_senders_signal_quality' in status: message["good_senders_signal"] = status['good_senders_signal_quality']
140+
if 'good_senders' in status: message["good_senders"] = status['good_senders']
141+
if 'good_and_bad_senders' in status: message["good_and_bad_senders"] = status['good_and_bad_senders']
142+
143+
if 'unparsed' in status: message["user_comment"] = status['unparsed']
144+
else:
145+
raise ValueError("WTF")
146+
147+
else:
148+
raise ValueError("WTF")
149+
150+
else:
151+
message = parse_aprs(aprs_message, reference_timestamp=reference_timestamp)
152+
if message['aprs_type'] == 'position' or message['aprs_type'] == 'status':
153+
try:
154+
message.update(parse_comment(message['comment'], dstcall=message['dstcall'], aprs_type=message['aprs_type']))
155+
except Exception:
156+
raise OgnParseError(f"dstcall: {message['dstcall']}, aprs_type: {message['aprs_type']}, comment: {message['comment']}")
42157

43158
if message['aprs_type'].startswith('position') and calculate_relations is True:
44159
positions[message['name']] = (message['longitude'], message['latitude'])
@@ -112,7 +227,7 @@ def parse_aprs(message, reference_timestamp=None):
112227

113228
'name': match.group('callsign'),
114229
'dstcall': match.group('dstcall'),
115-
'relay': match.group('relay') if match.group('relay') else None,
230+
'relay': match.group('relay'),
116231
'receiver_name': match.group('receiver'),
117232
'timestamp': createTimestamp(match_position_weather.group('time'), reference_timestamp),
118233
'latitude': parseAngle('0' + match_position_weather.group('latitude')) * # noqa: W504

0 commit comments

Comments
 (0)