File: qa_mobitex_to_datablocks.py

package info (click to toggle)
gr-satellites 5.8.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 10,836 kB
  • sloc: python: 29,546; cpp: 5,448; ansic: 1,247; sh: 118; makefile: 24
file content (132 lines) | stat: -rw-r--r-- 4,470 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Copyright 2025 Fabian P. Schmidt <kerel@mailbox.org>
#
# This file is part of gr-satellites
#
# SPDX-License-Identifier: GPL-3.0-or-later
#

from gnuradio import gr, blocks, gr_unittest
import numpy as np
import pmt

# bootstrap satellites module, even from build dir
try:
    import python as satellites
except ImportError:
    pass
else:
    import sys
    sys.modules['satellites'] = satellites

from satellites.mobitex_to_datablocks import (
    check_callsign_crc, compare_expected_callsign, decode_unknown_callsign,
    decode_control, encode_control,
)


class qa_mobitex_to_datablocks(gr_unittest.TestCase):
    def test_check_callsign_crc(self):
        fixture = [
            (b'DP0BEM', b'\x4d\xf7', True),
            (b'DP0BEX', b'\x4d\xf7', False),
        ]

        for callsign, crc, desired_result in fixture:
            actual_result = check_callsign_crc(callsign, crc)
            self.assertEqual(actual_result, desired_result)

    def test_compare_expected_callsign(self):
        fixture = [
            ((b'DP0BEM', b'\x4d\xf7', b'DP0BEM'), (b'\x4d\xf7', 0)),
            ((b'DQ0BEM', b'\x4d\xf7', b'DP0BEM'), (b'\x4d\xf7', 1)),
            ((b'EQ0BEM', b'\x4d\xf7', b'DP0BEM'), (b'\x4d\xf7', 2)),
            ((b'\x1b@@@L!', b'\x4d\xf7', b'DP0BEM'), (b'\x4d\xf7', 17)),
        ]

        for input, desired_output in fixture:
            callsign, crc, callsign_ref = input
            desired_crc_ref, desired_bit_errors = desired_output

            actual_crc_ref, actual_bit_errors = compare_expected_callsign(
                    callsign,
                    crc,
                    callsign_ref
                )
            self.assertEqual(actual_crc_ref, desired_crc_ref)
            self.assertEqual(actual_bit_errors, desired_bit_errors)

    def test_decode_unknown_callsign(self):
        fixture = [
            # No bit error
            ((b'DP0BEM', b'\x4d\xf7', 2), (b'DP0BEM', b'\x4d\xf7', 0)),
            # 1 bit error in callsign
            ((b'EP0BEM', b'\x4d\xf7', 2), (b'DP0BEM', b'\x4d\xf7', 1)),
            # 1 bit error in crc
            ((b'DP0BEM', b'\x5d\xf7', 2), (b'DP0BEM', b'\x4d\xf7', 1)),
            # 4 bit errors in callsign
            ((b'EQ0BEN', b'\x4d\xf7', 4), (b'DP0BEM', b'\x4d\xf7', 4)),
            # Bit error count exceeded
            ((b'EQ0BEN', b'\x4d\xf7', 2), None),
            # False-positive solutions when too many bit flips are allowed
            ((b'EQ1BEN', b'\x5d\xf6', 4), (b'EU1BEO', b'}\xf6', 3)),
        ]
        for input, desired_output in fixture:
            callsign, crc, max_bit_flips = input

            actual_output = decode_unknown_callsign(
                    callsign,
                    crc,
                    max_bit_flips,
                )

            if desired_output is None:
                self.assertIsNone(actual_output)
                continue

            desired_callsign, desired_crc, desired_bit_errors = desired_output
            actual_callsign, actual_crc, actual_bit_errors = actual_output
            self.assertEqual(actual_bit_errors, desired_bit_errors)

    def test_decode_control(self):
        fixture = [
            # No bit error
            ((0x3f, 0x02, 0xc6), ((0x3f, 0x02, 0xc6), 0)),
            # One bit errors
            ((0b0011_1011, 0x02, 0xc6), ((0x3f, 0x02, 0xc6), 1)),
            # Two bit errors
            ((0b0011_1010, 0x02, 0xc6), None),
        ]

        for control_and_fec, desired_result in fixture:
            actual_result = decode_control(*control_and_fec)
            if desired_result is None:
                self.assertIsNone(actual_result)
                continue

            actual_bytes = bytes(actual_result[0])
            actual_bit_errors = actual_result[1]

            desired_bytes = bytes(desired_result[0])
            desired_bit_errors = desired_result[1]

            self.assertEqual(actual_bytes, desired_bytes)
            self.assertEqual(actual_bit_errors, desired_bit_errors)

    def test_encode_control(self):
        fixture = [
            ((0x00, 0x00), 0x00),
            ((0x3f, 0x01), 0xc5),
            ((0x3f, 0x02), 0xc6),
            ((0xff, 0xff), 0xff),
        ]

        for control, desired_fec in fixture:
            actual_fec = encode_control(*control)
            self.assertEqual(actual_fec, desired_fec)


if __name__ == '__main__':
    gr_unittest.run(qa_mobitex_to_datablocks)