// // ADSBRunner.swift // LearnMapKit // // Created by Jacky Jack on 28/06/2024. // import Foundation import Collections struct ADSBLocation { let address: Int let lat: Double let long: Double //let alt: Int } struct ADSBAltitude { let address: Int let altitude: Int } struct ADSBICAOname { let address: Int let ICAOname: String } enum DataStreamType { case EMPTY case ADSB_ICAO case ADSB_LOCATION case ADSB_ALTITUDE } //get stream of decoded data, to tagged stream so all can be processed in sequence class ADSBDataQueue { //var icaoQueue: Deque = [] var icaoArray: Array = [] var altQueue: Deque = [] var locQueue: Deque = [] //var tagQueue: Deque<> = [] var tagArray: Array = [] func getNextTag() -> DataStreamType { if tagArray.count < 0 { return DataStreamType.EMPTY } return tagArray[tagArray.count-1] } func addIcaoName(_ address: Int, _ icaoname: String) { tagArray.append(DataStreamType.ADSB_ICAO) icaoArray.append(ADSBICAOname(address: address, ICAOname: icaoname)) } func addAltitude(_ address: Int, _ altitude: Int) { tagArray.append(DataStreamType.ADSB_ALTITUDE) altQueue.append(ADSBAltitude(address: address, altitude: altitude)) } func addLocation(_ address: Int, _ lat: Double, _ long: Double) { tagArray.append(DataStreamType.ADSB_LOCATION) locQueue.append(ADSBLocation(address: address, lat: lat, long: long)) } func getIcaoName() -> ADSBICAOname { if tagArray.count < 1 { print("ADSB tag Queue is empty") return ADSBICAOname(address:0,ICAOname: "TEmpty") } let tag = tagArray[tagArray.count-1] if tag != DataStreamType.ADSB_ICAO { print("ADSB Queue empty") 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 } return ret_icao_name } func getAltitude() -> ADSBAltitude { if tagArray.count < 1 { print("ADSB tag Queue is empry") return ADSBAltitude(address:0,altitude:0) } let tag = tagArray[tagArray.count-1] if tag != DataStreamType.ADSB_ALTITUDE { print("ADSB Queue empty") return ADSBAltitude(address:0,altitude:0) } tagArray.removeLast() return altQueue.popLast()! } func getLocation() -> ADSBLocation { if tagArray.count < 1 { print("ADSB tag Queue is empry") return ADSBLocation(address:0,lat:0.0,long:0.0) } 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) } tagArray.removeLast() return locQueue.popLast()! } func haveNum(_ num: Int) -> Bool { if (tagArray.count > num) { return true } return false } func getCount() -> Int { return tagArray.count } } class ADSBFileRunner { var filename: URL //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 if (checkIfFileExists(filename.path) == false) { print("Supplied path \(filename.path) doesnt exists") exit(1) } } func readFile() { //load the file with adsb data do { adsb_source = try String(contentsOfFile: filename.path) print("Loaded \(adsb_source.count) bytes") } catch { print("Couldn't load text from a file \(filename.path) \(error)") exit(1) } print("If there anything new in file") } func decode() { for line in self.adsb_source.components(separatedBy: .newlines) { var found=false do { if let tokenMatch = try matchADSBLong.prefixMatch(in: line) { //print("\(String(tokenMatch.output))") found = true let str = String(tokenMatch.output) let startIndex = str.index(str.startIndex, offsetBy: 1) let endIndex = str.index(str.endIndex, offsetBy: -2) let decoder = Decoder(String(str[startIndex...endIndex])) if decoder.DataFormat == 17 { if let d17 = decoder.getDataFormat17() { if (d17.TypeCode == 4) { if let indentification = d17.messageIdentification { tracker.addDF17Indentification(d17.AddressAnnounced, indentification.ICAOName) adsb_tag_stream.addIcaoName(d17.AddressAnnounced, tracker.getICAOname(d17.AddressAnnounced)!) } } else if (d17.TypeCode >= 9 && d17.TypeCode <= 18) { if let airbornposition = d17.messageAirbornPositon { tracker.addDF17AirBornPosition( d17.AddressAnnounced, airbornposition.Latitude, airbornposition.Longitude, airbornposition.Altitude, airbornposition.CPRFormat == 0 ) if let position = tracker.getPosition(d17.AddressAnnounced) { print("position: \(position)") adsb_tag_stream.addAltitude(d17.AddressAnnounced, tracker.getAltitude(d17.AddressAnnounced)!) let location = tracker.getPosition(d17.AddressAnnounced)! adsb_tag_stream.addLocation(d17.AddressAnnounced, location.0, location.1) } } } } } }; } catch { print("Error") } if (found == false) { print("Unknown adsb data line \(line)") } } self.decoded_status = true //try to free the string after decoded //adsb_source = "" for i in 0.. Bool { return self.decoded_status } func getPlainData(_ num_queries: Int) -> ADSBDataQueue { var ret = ADSBDataQueue() if adsb_tag_stream.haveNum(num_queries) { for _ in 0.. Int { return self.adsb_tag_stream.getCount() } }