diff options
author | Arturs Artamonovs <arturs.artamonovs@protonmail.com> | 2024-07-16 06:45:43 +0100 |
---|---|---|
committer | Arturs Artamonovs <arturs.artamonovs@protonmail.com> | 2024-07-16 06:45:43 +0100 |
commit | b32ecfab276fb8e1dff0e1d72ed819b548323328 (patch) | |
tree | c6b5b70754252520fd0b32513e76bb439b5bbfa5 /LearnMapKit | |
parent | 96cd6ab4bc219810779fe57158dfdf7627c5a5a0 (diff) | |
download | ADSBDecoder-b32ecfab276fb8e1dff0e1d72ed819b548323328.tar.gz ADSBDecoder-b32ecfab276fb8e1dff0e1d72ed819b548323328.zip |
Working implementation of ADSB loaded from file. Net1090 can read from dump1090 socket
Diffstat (limited to 'LearnMapKit')
-rw-r--r-- | LearnMapKit/ADSBRunner.swift | 110 | ||||
-rw-r--r-- | LearnMapKit/ContentView.swift | 85 | ||||
-rw-r--r-- | LearnMapKit/FlighState.swift | 138 | ||||
-rw-r--r-- | LearnMapKit/LearnMapKit.entitlements | 2 | ||||
-rw-r--r-- | LearnMapKit/LearnMapKitApp.swift | 26 |
5 files changed, 292 insertions, 69 deletions
diff --git a/LearnMapKit/ADSBRunner.swift b/LearnMapKit/ADSBRunner.swift index 6d2bbc5..e05978c 100644 --- a/LearnMapKit/ADSBRunner.swift +++ b/LearnMapKit/ADSBRunner.swift @@ -34,81 +34,91 @@ enum DataStreamType { //get stream of decoded data, to tagged stream so all can be processed in sequence class ADSBDataQueue { - var icaoQueue: Deque<ADSBICAOname> = [] + //var icaoQueue: Deque<ADSBICAOname> = [] + var icaoArray: Array<ADSBICAOname> = [] var altQueue: Deque<ADSBAltitude> = [] var locQueue: Deque<ADSBLocation> = [] - var tagQueue: Deque<DataStreamType> = [] + //var tagQueue: Deque<> = [] + var tagArray: Array<DataStreamType> = [] func getNextTag() -> DataStreamType { - if tagQueue.count < 0 { + if tagArray.count < 0 { return DataStreamType.EMPTY } - return tagQueue[tagQueue.count-1] + return tagArray[tagArray.count-1] } func addIcaoName(_ address: Int, _ icaoname: String) { - tagQueue.append(DataStreamType.ADSB_ICAO) - icaoQueue.append(ADSBICAOname(address: address, ICAOname: icaoname)) + tagArray.append(DataStreamType.ADSB_ICAO) + icaoArray.append(ADSBICAOname(address: address, ICAOname: icaoname)) } func addAltitude(_ address: Int, _ altitude: Int) { - tagQueue.append(DataStreamType.ADSB_ALTITUDE) + tagArray.append(DataStreamType.ADSB_ALTITUDE) altQueue.append(ADSBAltitude(address: address, altitude: altitude)) } func addLocation(_ address: Int, _ lat: Double, _ long: Double) { - tagQueue.append(DataStreamType.ADSB_LOCATION) + tagArray.append(DataStreamType.ADSB_LOCATION) locQueue.append(ADSBLocation(address: address, lat: lat, long: long)) } func getIcaoName() -> ADSBICAOname { - if tagQueue.count < 1 { - print("ADSB tag Queue is empry") - return ADSBICAOname(address:0,ICAOname: "") + if tagArray.count < 1 { + print("ADSB tag Queue is empty") + return ADSBICAOname(address:0,ICAOname: "TEmpty") } - let tag = tagQueue[tagQueue.count-1] + let tag = tagArray[tagArray.count-1] if tag != DataStreamType.ADSB_ICAO { print("ADSB Queue empty") - return ADSBICAOname(address:0,ICAOname: "") + return ADSBICAOname(address:0,ICAOname: "QEmpty") + } + tagArray.removeLast() + var ret_icao_name = ADSBICAOname(address:0, ICAOname: "Default") + if let last_icao_name = icaoArray.popLast() { + ret_icao_name = last_icao_name } - tagQueue.removeLast() - return icaoQueue.popLast()! + return ret_icao_name } func getAltitude() -> ADSBAltitude { - if tagQueue.count < 1 { + if tagArray.count < 1 { print("ADSB tag Queue is empry") return ADSBAltitude(address:0,altitude:0) } - let tag = tagQueue[tagQueue.count-1] + let tag = tagArray[tagArray.count-1] if tag != DataStreamType.ADSB_ALTITUDE { print("ADSB Queue empty") return ADSBAltitude(address:0,altitude:0) } - tagQueue.removeLast() + tagArray.removeLast() return altQueue.popLast()! } func getLocation() -> ADSBLocation { - if tagQueue.count < 1 { + if tagArray.count < 1 { print("ADSB tag Queue is empry") return ADSBLocation(address:0,lat:0.0,long:0.0) } - let tag = tagQueue[tagQueue.count-1] + let tag = tagArray[tagArray.count-1] if tag != DataStreamType.ADSB_LOCATION { print("ADSB Queue empty") return ADSBLocation(address:0,lat:0.0,long:0.0) } - tagQueue.removeLast() + tagArray.removeLast() return locQueue.popLast()! } func haveNum(_ num: Int) -> Bool { - if (tagQueue.count > num) { + if (tagArray.count > num) { return true } return false } + + func getCount() -> Int { + return tagArray.count + } } class ADSBFileRunner { @@ -117,13 +127,27 @@ class ADSBFileRunner { //track all airplanes var tracker = AirPlaneTracker() var adsb_source: String = "" + //should make it outside and use here? var adsb_tag_stream = ADSBDataQueue() + private var decoded_status: Bool = false init(filename:String) { self.filename = URL(fileURLWithPath:filename) } + init() { + self.filename = URL(fileURLWithPath:"") + } + + func setFileName(_ filename:String) { + self.filename = URL(fileURLWithPath: filename) + } + func openFile() { + if self.filename == URL(fileURLWithPath:"") { + print("File name for ADSBRunner not specified") + return + } print("File location [\(filename.absoluteString)]") //check if file excists @@ -139,7 +163,7 @@ class ADSBFileRunner { adsb_source = try String(contentsOfFile: filename.path) print("Loaded \(adsb_source.count) bytes") } catch { - print("Couldn't load text from a file \(filename.path)") + print("Couldn't load text from a file \(filename.path) \(error)") exit(1) } print("If there anything new in file") @@ -192,7 +216,47 @@ class ADSBFileRunner { print("Unknown adsb data line \(line)") } } + self.decoded_status = true //try to free the string after decoded //adsb_source = "" + for i in 0..<adsb_tag_stream.icaoArray.count { + print(adsb_tag_stream.icaoArray[i]) + } + print("Queue done") + } + + func jobDone() -> Bool { + return self.decoded_status + } + + func getPlainData(_ num_queries: Int) -> ADSBDataQueue { + var ret = ADSBDataQueue() + if adsb_tag_stream.haveNum(num_queries) { + + for _ in 0..<num_queries { + let nextTag = adsb_tag_stream.getNextTag() + if nextTag == DataStreamType.EMPTY { + return ret + } + if (nextTag == DataStreamType.ADSB_ALTITUDE) { + let alt = adsb_tag_stream.getAltitude() + ret.addAltitude(alt.address, alt.altitude) + } else if (nextTag == DataStreamType.ADSB_ICAO) { + let icao = adsb_tag_stream.getIcaoName() + ret.addIcaoName(icao.address, icao.ICAOname) + } else if (nextTag == DataStreamType.ADSB_LOCATION) { + let loc = adsb_tag_stream.getLocation() + ret.addLocation(loc.address, loc.lat, loc.long) + } + } + return ret + } else { + print("Plain data query is empty") + } + return ret + } + + func getCount() -> Int { + return self.adsb_tag_stream.getCount() } } diff --git a/LearnMapKit/ContentView.swift b/LearnMapKit/ContentView.swift index 08f4192..13ef64f 100644 --- a/LearnMapKit/ContentView.swift +++ b/LearnMapKit/ContentView.swift @@ -9,6 +9,31 @@ import SwiftUI import MapKit import Collections +struct FlightView: View { + + var evilClass: FlightState + + var body: some View { + //let i = evilClass.flight.count + let pos = CLLocationCoordinate2D(latitude: 55.80159, longitude:-3.13154) + Map() { + ForEach(0..<10, id:\.self) {i in + Annotation("plane\(i)", coordinate: pos) { + ZStack { + RoundedRectangle(cornerRadius: 10) + .fill(.background) + RoundedRectangle(cornerRadius: 10) + .stroke(.secondary,lineWidth: 5) + Image(systemName:"airplane.circle.fill") + .resizable() + .frame(width:20,height: 20) + } + }//.annotationTitles(.hidden) + } + } + } +} + struct ContentView: View { @State private var region = MKCoordinateRegion() @@ -17,6 +42,7 @@ struct ContentView: View { @Binding var pos_queue: Deque<ADSBLocation> @EnvironmentObject var evilClass: FlightState + let initialPosition: MapCameraPosition = { let center = CLLocationCoordinate2D(latitude: 55.90159, longitude:-3.53154) let span = MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1) @@ -53,7 +79,7 @@ struct ContentView: View { } Button("7") { print("Pressed 7") - print(evilClass.update_postions.count) + //print(evilClass.update_postions.count) } } .border(.blue) @@ -61,7 +87,7 @@ struct ContentView: View { //.padding() Map(initialPosition: initialPosition) { - Annotation("plane1", coordinate: position1) { + /*Annotation("plane1", coordinate: position1) { ZStack { RoundedRectangle(cornerRadius: 10) .fill(.background) @@ -104,7 +130,46 @@ struct ContentView: View { .resizable() .frame(width:20,height: 20) } - }.annotationTitles(.hidden) + }.annotationTitles(.hidden)*//* + ForEach(0..<evilClass.flight.count, id:\.self) { _ in + Annotation("plane\(0)", coordinate: CLLocationCoordinate2D(latitude: evilClass.flight[0]?.lat!, longitude: evilClass.flight[0]?.long!)) { + ZStack { + RoundedRectangle(cornerRadius: 10) + .fill(.background) + RoundedRectangle(cornerRadius: 10) + .stroke(.secondary,lineWidth: 5) + Image(systemName:"airplane.circle.fill") + .resizable() + .frame(width:20,height: 20) + } + }.annotationTitles(.hidden) + }*/ + //let c = self.evilClass.flight.count + /*ForEach(0..<self.evilClass.flight.count, id:\.self) { exp in + //print("Draw annotation") + //Annotation("plane\(exp+4)", coordinate: CLLocationCoordinate2D(latitude: 55.80159, longitude:-3.53154+Double(exp)*0.1)) { + Annotation("plane\(exp+4)", coordinate: CLLocationCoordinate2D(latitude: self.evilClass.flight[exp]!.lat, longitude:self.evilClass.flight[exp]!.long)) { + Image(systemName:"airplane.circle.fill") + .resizable() + .frame(width:20,height: 20) + } + }*/ + ForEach(self.evilClass.flight.sorted(by: { $0.key < $1.key} ), id:\.key) { k in + Annotation("\(k.key)", coordinate: CLLocationCoordinate2D(latitude: self.evilClass.flight[k.key]!.lat, longitude:self.evilClass.flight[k.key]!.long)) { + VStack { + ZStack { + RoundedRectangle(cornerRadius: 10) + .fill(.background) + RoundedRectangle(cornerRadius: 10) + .stroke(.secondary,lineWidth: 5) + Image(systemName:"airplane.circle.fill") + .resizable() + .frame(width:20,height: 20) + } + Text("\(k.value.ICAOName)") + } + }.annotationTitles(.hidden) + } } .padding() .border(.green) @@ -126,13 +191,25 @@ struct ContentView: View { print(error) } } - + drawFlights() } .padding() .border(.red) .layoutPriority(1) } + + func mapAction() { + print("This is called") + } + + @ViewBuilder + func drawFlights() -> some View { + let c = self.evilClass.flight.count + ForEach(0..<c, id:\.self) { exp in + //Annotation("plane4", coordinate: position4) + } + } } //#Preview { diff --git a/LearnMapKit/FlighState.swift b/LearnMapKit/FlighState.swift index f3895cb..cfb34f1 100644 --- a/LearnMapKit/FlighState.swift +++ b/LearnMapKit/FlighState.swift @@ -8,38 +8,144 @@ import Foundation import Collections +class FlightTracker { + var last_time_seen: Int = 0 + var ICAOName_avaliable = false + @Published var ICAOName = "" + var Position_avaliable = false + @Published var long:Double = 0.0 + @Published var lat:Double = 0.0 + var FromTo_avaliable = false + var flightFrom:String = "" + var flightTo:String = "" +} + class FlightState: ObservableObject { - @Published var name = "Some Name" - @Published var isEnabled = false var timer: Timer? - var update_postions: Deque<ADSBLocation> = [] + //default location currently for testing var fromFile: Bool = false + @Published var flight:[Int:FlightTracker] = [:] + + //configuration options + let default_file_path = "/Users/jackyjack/Downloads/2024_05_27_raw_adsb.txt" + let process_per_second = 120 + init() { var count = 0 - let ADSBtask = ADSBFileRunner(filename: "") + //let ADSBtask = ADSBFileRunner(filename: "") + let adsb_file = ADSBFileRunner(filename: self.default_file_path) + + + DispatchQueue.global(qos: .background).sync { + print("Open file") + adsb_file.openFile() + adsb_file.readFile() + } + + DispatchQueue.global(qos: .background).async { + print("Start decoding data") + adsb_file.decode() + print("Stop decoding data") + } + + //once a second read some data from decoded queue timer = Timer.scheduledTimer( withTimeInterval: 1, repeats: true ) { _ in - - //queue.append(MapADSBData(lat: 0.0, long: 0.0, alt: 1)) - - //let timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in - print("Evil object \(count)") - //ADSBtask.runFromFile() - self.update_postions.append(ADSBLocation(address: 0, lat: 0.0, long: 0.0)) - // print(update_postions.count) - count += 1 - //} + //get the 10 entries if there is + if adsb_file.jobDone() { + print("Decoding done let get some data \(adsb_file.getCount())") + //if adsb_file + if adsb_file.getCount() > self.process_per_second { + let data = adsb_file.getPlainData(self.process_per_second) + //print(data.getCount()) + for idx in 0..<data.getCount() { + let nextTag = data.getNextTag() + if nextTag == DataStreamType.ADSB_ALTITUDE { + let _ = data.getAltitude() +#warning("Implement this") + } else if (nextTag == DataStreamType.ADSB_ICAO) { + let icao = data.getIcaoName() + print("Tag icao \(icao) count:\(data.icaoArray.count)") + self.addIcaoName(icao.address, icao.ICAOname) + } else if (nextTag == DataStreamType.ADSB_LOCATION) { + print("tag location") + let loc = data.getLocation() + self.addLocation(loc.address, loc.lat, loc.long) + } + } + + } else { + print("Data stream is empty") + } + } } } + init(filename: String) { - + #warning("not implemented at all") + } + + func addLocation(_ address: Int, _ lat: Double, _ long: Double) { + if flight[address] == nil { + flight[address] = FlightTracker() + flight[address]?.last_time_seen = Int(Date().timeIntervalSince1970) + flight[address]?.Position_avaliable = true + flight[address]?.lat = lat + flight[address]?.long = long + print("new location") + return + } else { + if let f = flight[address] { + f.last_time_seen = Int(Date().timeIntervalSince1970) + f.Position_avaliable = true + f.lat = lat + f.long = long + print("Update location \(flight.count)") + return + } + + } + print("No update?") + } + + func addIcaoName(_ address: Int, _ icaoname: String) { + if flight[address] == nil { + flight[address] = FlightTracker() + flight[address]?.last_time_seen = Int(Date().timeIntervalSince1970) + flight[address]?.ICAOName_avaliable = true + flight[address]?.ICAOName = icaoname + print("new flight name added \(icaoname)") + return + } else { + if let f = flight[address] { + f.last_time_seen = Int(Date().timeIntervalSince1970) + if f.ICAOName_avaliable == false{ + f.ICAOName_avaliable = true + f.ICAOName = icaoname + print("flight timestamp updated") + return + } + } + } + print("no update?!") } - func loadFromFile() { + func addNewFlight() { } + + //loop over and if expired then remove + func removeExpiredFlight() { + for (address,el) in self.flight { + //if on the map more then 1 minute + if el.last_time_seen+60 < Int(Date().timeIntervalSince1970) { + self.flight.removeValue(forKey: address) + } + } + } + } diff --git a/LearnMapKit/LearnMapKit.entitlements b/LearnMapKit/LearnMapKit.entitlements index 18aff0c..61b4b47 100644 --- a/LearnMapKit/LearnMapKit.entitlements +++ b/LearnMapKit/LearnMapKit.entitlements @@ -4,6 +4,8 @@ <dict> <key>com.apple.security.app-sandbox</key> <true/> + <key>com.apple.security.files.downloads.read-only</key> + <true/> <key>com.apple.security.files.user-selected.read-only</key> <true/> </dict> diff --git a/LearnMapKit/LearnMapKitApp.swift b/LearnMapKit/LearnMapKitApp.swift index 5fa170a..1b64510 100644 --- a/LearnMapKit/LearnMapKitApp.swift +++ b/LearnMapKit/LearnMapKitApp.swift @@ -10,8 +10,6 @@ import Collections //https://www.hackingwithswift.com/quick-start/swiftui/how-to-run-code-when-your-app-launches - - @main struct LearnMapKitApp: App { @@ -21,30 +19,6 @@ struct LearnMapKitApp: App { init() { print("Init app") - var update_postions: Deque<ADSBLocation> = [] - DispatchQueue.global(qos: .background).sync { - print("Dispatch") - //var count = 0 - - - //let ADSBtask = ADSBRunner() - //queue.append(MapADSBData(lat: 0.0, long: 0.0, alt: 1)) - /* - let timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in - print("Timer fired! \(count)") - ADSBtask.runFromFile() - update_postions.append(MapADSBData(lat: 0.0, long: 0.0, alt: 1)) - print(update_postions.count) - count += 1 - }*/ - print("Exit dispatch") - } - - //push all new data to state queue from a runner - DispatchQueue.global(qos: .background).sync { - // Update the UI on the main thread - let c = queue.count - } } |