From 3d3d88cfe057d5194b51a0c61eff31e4bdc890fe Mon Sep 17 00:00:00 2001 From: infinitesniper <64354127+infinitesniper@users.noreply.github.com> Date: Sun, 25 Oct 2026 13:44:42 +0800 Subject: [PATCH 1/2] Decode numeric overlays in compressed positions --- aprslib/parsing/position.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/aprslib/parsing/position.py b/aprslib/parsing/position.py index e66c502..32da6a3 100644 --- a/aprslib/parsing/position.py +++ b/aprslib/parsing/position.py @@ -98,6 +98,9 @@ def parse_compressed(body): body = body[13:] symbol_table = compressed[0] + # APRS101: compressed numeric overlays use a-j instead of 0-9. + if 'a' <= symbol_table <= 'j': + symbol_table = chr(ord('0') + ord(symbol_table) - ord('a')) symbol = compressed[9] try: From e97f033837e7cd899d882b447c70b112fab83735 Mon Sep 17 00:00:00 2001 From: infinitesniper <64354127+infinitesniper@users.noreply.github.com> Date: Sun, 25 Oct 2026 13:53:48 +0800 Subject: [PATCH 2/2] Cover compressed numeric overlays and unchanged symbol tables --- tests/test_parse_position.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/test_parse_position.py b/tests/test_parse_position.py index 4a2287b..0dc65a5 100644 --- a/tests/test_parse_position.py +++ b/tests/test_parse_position.py @@ -166,5 +166,18 @@ def test_position_packet_optional_course(self): _, result = parse_position(packet_type, packet) self.assertEqual(expected, result) +class ParseCompressedPosition(unittest.TestCase): + def test_numeric_symbol_overlays(self): + for encoded, expected in zip('abcdefghij', '0123456789'): + _, result = parse_position('!', encoded + '5L!!<*e7#7P[') + self.assertEqual(expected, result['symbol_table']) + self.assertEqual('#', result['symbol']) + + def test_other_symbol_tables(self): + for symbol_table in '/\\ABCDEFGHIJKLMNOPQRSTUVWXYZ': + _, result = parse_position('!', symbol_table + '5L!!<*e7#7P[') + self.assertEqual(symbol_table, result['symbol_table']) + + if __name__ == '__main__': unittest.main()