summaryrefslogtreecommitdiff
path: root/ADSBDecoder/Decoder.swift
blob: 95f798bb5deb5d7cec5f74ab3c5c18c369a0cabf (plain) (blame)
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
//
//  Decoder.swift
//  ADSBDecoder
//
//  Created by Jacky Jack on 28/05/2024.
//

import Foundation

func BarometricAltitudeFeat(_ altitude: UInt16) -> Int {
    let QBit = (altitude>>4)&0x1
    if QBit == 1 {
        //remove qbit
        let part1:UInt16 = altitude&0xf
        let part2:UInt16 = (altitude>>1)&0x7ff0
        let altitude25 = part1 + part2
        print("altitude2 \(altitude25) ")
        return Int(altitude25)*25-1000
    }
    return Int(altitude)*100-1000
}

class Decoder {
    var adsb_data: String = ""
    var DataFormat: UInt32 = 0;
    
    init (_ adsb_data: String) {
        print(adsb_data)
        self.adsb_data = adsb_data
        //get the first 8 bits as integer
        let startI =  adsb_data.startIndex
        let endI = adsb_data.index(startI, offsetBy: 1)
        let firstByteString = adsb_data[startI...endI]
        //print("\(firstByteString)")
        if let ControlMsg = UInt32(firstByteString, radix: 16) {
            //print("ControlMsg = \(ControlMsg)")
            let CM_DataFormat = (ControlMsg&0xF8)>>3
            DataFormat = CM_DataFormat
            //let CM_TranspoderCapability = ControlMsg&(0x7)
        }
        print("Data Format \(DataFormat)")
    }
    
    func getDataFormat17() -> DataFormat17? {
        
        if (DataFormat != 17) {
            return nil
        }
        //let startI =  adsb_data.index(adsb_data.startIndex, offsetBy: 1)
        //let endI = adsb_data.index(adsb_data.endIndex, offsetBy: -1)
        //let adsbData = adsb_data[startI...endI]
        let ret:DataFormat17 = DataFormat17(adsb_data)
        
        
        
        return ret;
    }
    
    func getDataFormat18() {
        print("Not implemented")
    }
    
}

func ICAOAlphabet(_ code: UInt8) -> String {
    if ((code>=1) && (code<=26)) {
        return String(UnicodeScalar(code+64))
    } else if ((code >= 48)&&(code<=57)) {
        return String(UnicodeScalar(code))
    } else if (code==32) {
        return " "
    }
    return "#"
}

func ICAO2String(_ b1: UInt8, _ b2: UInt8, _ b3: UInt8, _ b4: UInt8, _ b5: UInt8, _ b6: UInt8, _ b7: UInt8, _ b8: UInt8) -> String {
    return ICAOAlphabet(b1)+ICAOAlphabet(b2)+ICAOAlphabet(b3)+ICAOAlphabet(b4)+ICAOAlphabet(b5)+ICAOAlphabet(b6)+ICAOAlphabet(b7)+ICAOAlphabet(b8)
}

class DataFormat17 {
    
    let DataFormat=17 //0:5
    var Capability=0  //5:7
    var AddressAnnounced=0 //8:31
    var TypeCode=0 //32:36
    var MovementField=0//37:43
    var HeadingBit=0//44
    var HeadingField=0//45:51
    var CPROddEven=0//53
    var CPRlat=0//54:70
    var CPRlon=0//71:87
    var ParityIntegrity=0//88-111
    
    init(_ adsb_data: String) {
        //print("Dataformat: 17!")
        //print(adsb_data)
        
        var bindata:[UInt8] = []
        
        var startN = adsb_data.startIndex
        var endN = adsb_data.index(startN, offsetBy: 1)
        var count=0//start index value
        while (count<adsb_data.count) {
            let u8 = UInt8(adsb_data[startN...endN], radix: 16)!
            //print(adsb_data[startN...endN])
            bindata.append(u8)
            count += 2
            if (count<adsb_data.count) {
                startN = adsb_data.index(startN, offsetBy: 2)
                endN = adsb_data.index(startN, offsetBy: 1)
            }
        }
        print(bindata)
        
        //Decode Capability
        let cap = (bindata[0]>>1)&0x7
        print(String(format: "cap %02x", cap))
        Capability = Int(cap)
        
        //Decode Address Announcement
        let address_ann = UInt32(bindata[1])<<16 + UInt32(bindata[2])<<8 + UInt32(bindata[3])
        print(String(format: "address %06x", address_ann))
        
        AddressAnnounced = Int(address_ann)
        
        //Decode Type Code
        let tc_byte = bindata[4] >> 3
        print(String(format: "tc %02d", tc_byte))
        
        TypeCode = Int(tc_byte)
                
        if (tc_byte == 4) {
            let msg = ADSBTypeCode4(bindata[4...10])
            print("=====ADSB MESSSGE 04 =======")
            print(msg)
            print("============================")
        } else if (tc_byte == 11) {
            let msg = ADSBTypeCode11(bindata[4...10])
            print("=====ADSB MESSSGE 11 =======")
            print(msg)
            print("============================")
        } else if (tc_byte == 19) {
            print("Byte 19")
        } else {
            print("Unknow TC byte")
            /*
            //Decode Movement Field
            let mov_byte = (bindata[4]&0x7) + (bindata[5]>>5)
            print(String(format: "mov %02x", mov_byte))
            
            //Heading Bit
            let heading_bit = (bindata[5]>>3)&0x1
            print(String(format: "heading %02x", heading_bit))
            
            //Heading direction
            let heading_direction = (bindata[5]&0xF)<<3+(bindata[6]>>4)&0xF
            print(String(format: "hdir %02x", heading_direction))
            
            //CPR Odd/Even
            let cpr_odd_even = (bindata[6]>>2)&0x1;
            print(String(format: "cpr %02x", cpr_odd_even))
            
            //CPR lat
            let cpr_lat = (bindata[6]&0x7)<<14 + (bindata[7]<<7) + (bindata[8]>>1)
            print(String(format: "cpr lat %06x", cpr_lat))
            
            //CPR lon
            let cpr_lon = ((bindata[8]&0x1)<<16) + (bindata[9]<<8) + (bindata[10])
            print(String(format: "cpr lon %06x", cpr_lon))
            */
        }
    }
}

class ADSBTypeCode4: CustomStringConvertible {
    var TypeCode:Int = 4
    var Category:Int = 0
    var ICAOName:String
    
    init(_ bindata:ArraySlice<UInt8>) {
        let cat = bindata[4]&0x7
        Category = Int(cat)
        let char_0 = bindata[5]>>2
        let char_1 = (bindata[5]&0x3)<<4 + bindata[6]>>4
        let char_2 = (bindata[6]&0xf)<<2 + (bindata[7]>>6)&0x3
        let char_3 = (bindata[7])&0x3f
        let char_4 = bindata[8]>>2
        let char_5 = (bindata[8]&0x3)<<4 + bindata[9]>>4
        let char_6 = (bindata[9]&0xf)<<2 + (bindata[10]>>6)
        let char_7 = bindata[10]&0x3f
        
        print(char_0, char_1, char_2,char_3,char_4,char_5,char_6,char_7)
        ICAOName = ICAO2String(char_0, char_1, char_2, char_3, char_4, char_5, char_6, char_7)
        //print("ICAO name \(ICAOName)")
    }
    
    var description: String {
        let description = "TypeCode \(TypeCode) Cat \(Category) Flight name \(ICAOName)"
        return description
    }
}

class ADSBTypeCode11:CustomStringConvertible {
    var TypeCode:Int = 11
    var SurveillanceStatus: Int = 0
    var SingleAntennaFlag: Int = 0
    var Altitude: Int = 0
    var Time: Int = 0
    var CPRFormat: Int = 0
    var Latitude: Int = 0
    var Longitude: Int = 0
    
    init(_ bindata:ArraySlice<UInt8>) {
        let ss = (bindata[4]>>1)&(0x3)
        SurveillanceStatus = Int(ss)
        let saf = bindata[5]&0x1
        SingleAntennaFlag = Int(saf)
        let altitude = UInt16(bindata[5])<<4 + (UInt16(bindata[6])>>4)&0xf
        print(altitude)
        Altitude = BarometricAltitudeFeat(altitude)
        let time = (bindata[6]>>3)&0x1
        Time = Int(time)
        let cpr = (bindata[6]>>2)&0x1
        CPRFormat = Int(cpr)
        let lat:UInt32 = UInt32(bindata[6]&0x3)<<15 + UInt32(bindata[7])<<7 + UInt32(bindata[8]>>1)
        Latitude = Int(lat)
        let lon:UInt32 = UInt32(bindata[8]&0x1)<<16 + UInt32(bindata[9])<<8 + UInt32(bindata[10])
        Longitude = Int(lon)
    }
    
    var description: String {
        var description = "SS \(SurveillanceStatus) SAF \(SingleAntennaFlag) Altitude \(Altitude)ft \n"
        description += "Time \(Time) CPR \(CPRFormat) \n"
        description += "Lat \(Latitude) Long \(Longitude)"
        return description
    }
}

class DataFormat18 {
    init(_ adsb_data: String) {
        print("Dataformat: 18")
        print(adsb_data)
    }
}