From 7260245e15fe47a303c183f76993b59822098a45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Gru=CC=88ndger?= Date: Sat, 20 Jul 2019 11:11:19 +0200 Subject: [PATCH] Changed telnet parser from fixed size to regex --- ogn/parser/pattern.py | 24 +++++++++++ ogn/parser/telnet_parser.py | 67 ++++++++++++++++--------------- tests/parser/test_parse_telnet.py | 9 ++++- 3 files changed, 66 insertions(+), 34 deletions(-) diff --git a/ogn/parser/pattern.py b/ogn/parser/pattern.py index 9896943..6467a5f 100644 --- a/ogn/parser/pattern.py +++ b/ogn/parser/pattern.py @@ -114,6 +114,30 @@ PATTERN_RECEIVER_STATUS_COMMENT = re.compile(r""" )? """, re.VERBOSE | re.MULTILINE) +PATTERN_TELNET_50001 = re.compile(r""" + (?P\d\.\d+)sec:(?P\d+\.\d+)MHz:\s+ + (?P\d):(?P\d):(?P
[A-F0-9]{6})\s + (?P\d{6}):\s + \[\s*(?P[+-]\d+\.\d+),\s*(?P[+-]\d+\.\d+)\]deg\s* + (?P\d+)m\s* + (?P[+-]\d+\.\d+)m/s\s* + (?P\d+\.\d+)m/s\s* + (?P\d+\.\d+)deg\s* + (?P[+-]\d+\.\d+)deg/sec\s* + (?P\d+)\s* + (?P[0-9x]+)m\s* + (?P\d+)(?P[f_])(?P[o_])\s* + (?P[+-]\d+\.\d+)kHz\s* + (?P\d+\.\d+)/(?P\d+\.\d+)dB/(?P\d+)\s+ + (?P\d+)e\s* + (?P\d+\.\d+)km\s* + (?P\d+\.\d+)deg\s* + (?P[+-]\d+\.\d+)deg\s* + (?P\+)?\s* + \?\s* + R?\s* + (B(?P\d+))? +""", re.VERBOSE | re.MULTILINE) # The following regexp patterns are part of the ruby ogn-client. # source: https://github.com/svoop/ogn_client-ruby diff --git a/ogn/parser/telnet_parser.py b/ogn/parser/telnet_parser.py index 45963c5..aea95ab 100644 --- a/ogn/parser/telnet_parser.py +++ b/ogn/parser/telnet_parser.py @@ -1,40 +1,43 @@ +import re from datetime import datetime -from ogn.parser import ParseError from ogn.parser.utils import createTimestamp +from ogn.parser.pattern import PATTERN_TELNET_50001 + +telnet_50001_pattern = re.compile(PATTERN_TELNET_50001) def parse(telnet_data): reference_timestamp = datetime.utcnow() - try: - return {'pps_offset': float(telnet_data[0:5]), - 'frequency': float(telnet_data[9:16]), - 'aircraft_type': int(telnet_data[20:24]), - 'address_type': int(telnet_data[25]), - 'address': telnet_data[27:33], - 'timestamp': createTimestamp(telnet_data[34:40] + 'h', reference_timestamp), - 'latitude': float(telnet_data[43:53]), - 'longitude': float(telnet_data[54:64]), - 'altitude': int(telnet_data[68:73]), - 'climb_rate': float(telnet_data[74:80]), - 'ground_speed': float(telnet_data[83:89]), - 'track': float(telnet_data[92:98]), - 'turn_rate': float(telnet_data[101:107]), - 'magic_number': int(telnet_data[114:116]), - 'gps_status': telnet_data[117:122], - 'channel': int(telnet_data[124:126]), - 'flarm_timeslot': telnet_data[126] == 'f', - 'ogn_timeslot': telnet_data[127] == 'o', - 'frequency_offset': float(telnet_data[128:134]), - 'decode_quality': float(telnet_data[137:142]), - 'signal_quality': float(telnet_data[143:147]), - 'demodulator_type': int(telnet_data[150:151]), - 'error_count': float(telnet_data[151:154]), - 'distance': float(telnet_data[155:162]), - 'bearing': float(telnet_data[164:170]), - 'phi': float(telnet_data[173:179]), - 'multichannel': telnet_data[183] == '+'} - - except Exception: - raise ParseError + match = telnet_50001_pattern.match(telnet_data) + if match: + return {'pps_offset': float(match.group('pps_offset')), + 'frequency': float(match.group('frequency')), + 'aircraft_type': int(match.group('aircraft_type')), + 'address_type': int(match.group('address_type')), + 'address': match.group('address'), + 'timestamp': createTimestamp(match.group('timestamp') + 'h', reference_timestamp), + 'latitude': float(match.group('latitude')), + 'longitude': float(match.group('longitude')), + 'altitude': int(match.group('altitude')), + 'climb_rate': float(match.group('climb_rate')), + 'ground_speed': float(match.group('ground_speed')), + 'track': float(match.group('track')), + 'turn_rate': float(match.group('turn_rate')), + 'magic_number': int(match.group('magic_number')), + 'gps_status': match.group('gps_status'), + 'channel': int(match.group('channel')), + 'flarm_timeslot': match.group('flarm_timeslot') == 'f', + 'ogn_timeslot': match.group('ogn_timeslot') == 'o', + 'frequency_offset': float(match.group('frequency_offset')), + 'decode_quality': float(match.group('decode_quality')), + 'signal_quality': float(match.group('signal_quality')), + 'demodulator_type': int(match.group('demodulator_type')), + 'error_count': float(match.group('error_count')), + 'distance': float(match.group('distance')), + 'bearing': float(match.group('bearing')), + 'phi': float(match.group('phi')), + 'multichannel': match.group('multichannel') == '+'} + else: + return None diff --git a/tests/parser/test_parse_telnet.py b/tests/parser/test_parse_telnet.py index ee4a451..4f60a74 100644 --- a/tests/parser/test_parse_telnet.py +++ b/tests/parser/test_parse_telnet.py @@ -14,11 +14,11 @@ class TestStringMethods(unittest.TestCase): parse('This is rubbish') @mock.patch('ogn.parser.telnet_parser.datetime') - def test_telnet_parse(self, datetime_mock): + def test_telnet_parse_complete(self, datetime_mock): # set the utcnow-mock near to the time in the test string datetime_mock.utcnow.return_value = datetime(2015, 1, 1, 10, 0, 55) - message = parse('0.181sec:868.394MHz: 1:2:DDA411 103010: [ +50.86800, +12.15279]deg 988m +0.1m/s 25.7m/s 085.4deg -3.5deg/sec 5 03x04m 01f_-12.61kHz 5.8/15.5dB/2 10e 30.9km 099.5deg +1.1deg + ?') + message = parse('0.181sec:868.394MHz: 1:2:DDA411 103010: [ +50.86800, +12.15279]deg 988m +0.1m/s 25.7m/s 085.4deg -3.5deg/sec 5 03x04m 01f_-12.61kHz 5.8/15.5dB/2 10e 30.9km 099.5deg +1.1deg + ? R B8949') self.assertEqual(message['pps_offset'], 0.181) self.assertEqual(message['frequency'], 868.394) @@ -48,6 +48,11 @@ class TestStringMethods(unittest.TestCase): self.assertEqual(message['phi'], 1.1) self.assertEqual(message['multichannel'], True) + def test_telnet_parse_corrupt(self): + message = parse('0.397sec:868.407MHz: sA:1:784024 205656: [ +5.71003, +20.48951]deg 34012m +14.5m/s 109.7m/s 118.5deg +21.0deg/sec 0 27x40m 01_o +7.03kHz 17.2/27.0dB/2 12e 4719.5km 271.1deg -8.5deg ? R B34067') + + self.assertIsNone(message) + if __name__ == '__main__': unittest.main()