File: altitude.py

package info (click to toggle)
gr-air-modes 0.0.20210211-3.1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,536 kB
  • sloc: python: 12,651; cpp: 496; ansic: 52; makefile: 15
file content (144 lines) | stat: -rw-r--r-- 5,581 bytes parent folder | download | duplicates (3)
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
133
134
135
136
137
138
139
140
141
142
143
144
#!/usr/bin/env python
#
# Copyright 2010, 2012 Nick Foster
# 
# This file is part of gr-air-modes
# 
# gr-air-modes is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
# 
# gr-air-modes is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with gr-air-modes; see the file COPYING.  If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#

# For reference into the methodology used to decode altitude,
# see RTCA DO-181D p.42

from air_modes.exceptions import *

def decode_alt(alt, bit13):
        mbit = alt & 0x0040
        qbit = alt & 0x0010
        
        if mbit and bit13:
                #nobody uses metric altitude: AFAIK, it's an orphaned part of
                #the spec. haven't seen it in three years. as a result, replies
                #with mbit set can be considered spurious, and so we discard them here.
                
                #bits 20-25, 27-31 encode alt in meters
                #remember that bits are LSB (bit 20 is MSB)
                #meters_alt = 0
                #for (shift, bit) in enumerate(range(31,26,-1)+range(25,19,-1)):
                #       meters_alt += ((alt & (1<<bit)) != 0) << shift
                #decoded_alt = meters_alt / 0.3048
                raise MetricAltError

        if qbit: #a mode S-style reply
                #bit13 is false for BDS0,5 ADS-B squitters, and is true otherwise
                if bit13:
                        #in this representation, the altitude bits are as follows:
                        # 12 11 10 9 8 7 (6) 5 (4) 3 2 1 0
                        # so bits 6 and 4 are the M and Q bits, respectively.
                        tmp1 = (alt & 0x3F80) >> 2
                        tmp2 = (alt & 0x0020) >> 1
                else:
                        tmp1 = (alt & 0x1FE0) >> 1
                        tmp2 = 0

                decoded_alt = ((alt & 0x0F) | tmp1 | tmp2) * 25 - 1000

        else: #a mode C-style reply
                  #okay, the order they come in is:
                  #C1 A1 C2 A2 C4 A4 X B1 D1 B2 D2 B4 D4
          #the order we want them in is:
          #D2 D4 A1 A2 A4 B1 B2 B4
          #so we'll reassemble into a Gray-coded representation

                if bit13 is False:
                        alt = (alt & 0x003F) | (alt & 0x0FC0 << 1)

                C1 = 0x1000
                A1 = 0x0800
                C2 = 0x0400
                A2 = 0x0200     #this represents the order in which the bits come
                C4 = 0x0100
                A4 = 0x0080
                B1 = 0x0020
                D1 = 0x0010
                B2 = 0x0008
                D2 = 0x0004
                B4 = 0x0002
                D4 = 0x0001

                bigpart =  ((alt & B4) >> 1) \
                                 + ((alt & B2) >> 2) \
                                 + ((alt & B1) >> 3) \
                                 + ((alt & A4) >> 4) \
                                 + ((alt & A2) >> 5) \
                                 + ((alt & A1) >> 6) \
                                 + ((alt & D4) << 6) \
                                 + ((alt & D2) << 5)

                #bigpart is now the 500-foot-resolution Gray-coded binary part
                decoded_alt = gray2bin(bigpart)
                #real_alt is now the 500-foot-per-tick altitude

                cbits =   ((alt & C4) >> 8) + ((alt & C2) >> 9) + ((alt & C1) >> 10)
                cval = gray2bin(cbits) #turn them into a real number

                if cval == 7:
                        cval = 5 #not a real gray code after all

                if decoded_alt % 2:
                        cval = 6 - cval #since the code is symmetric this unwraps it to see whether to subtract the C bits or add them

                decoded_alt *= 500 #take care of the A,B,D data
                decoded_alt += cval * 100 #factor in the C data
                decoded_alt -= 1300 #subtract the offset

        return decoded_alt

def gray2bin(gray):
        i = gray >> 1

        while i != 0:
                gray ^= i
                i >>= 1

        return gray

def encode_alt_modes(alt, bit13):
        mbit = False
        qbit = True
        encalt = (int(alt) + 1000) / 25

        if bit13 is True:
                tmp1 = (encalt & 0xfe0) << 2
                tmp2 = (encalt & 0x010) << 1
        else:
                tmp1 = (encalt & 0xff8) << 1
                tmp2 = 0

        return (encalt & 0x0F) | tmp1 | tmp2 | (mbit << 6) | (qbit << 4)

if __name__ == "__main__":
        try:
                for alt in range(-1000, 101400, 25):
                        dec = decode_alt(encode_alt_modes(alt, False), False)
                        if dec != alt:
                                print("Failure at %i with bit13 clear (got %s)" % (alt, dec))
                for alt in range(-1000, 101400, 25):
                        dec = decode_alt(encode_alt_modes(alt, True), True)
                        if dec != alt:
                                print("Failure at %i with bit13 set (got %s)" % (alt, dec))
        except MetricAltError:
                print("Failure at %i due to metric alt bit" % alt)