summaryrefslogtreecommitdiff
path: root/LearnMapKit
diff options
context:
space:
mode:
authorArturs Artamonovs <arturs.artamonovs@protonmail.com>2024-07-16 06:45:43 +0100
committerArturs Artamonovs <arturs.artamonovs@protonmail.com>2024-07-16 06:45:43 +0100
commitb32ecfab276fb8e1dff0e1d72ed819b548323328 (patch)
treec6b5b70754252520fd0b32513e76bb439b5bbfa5 /LearnMapKit
parent96cd6ab4bc219810779fe57158dfdf7627c5a5a0 (diff)
downloadADSBDecoder-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.swift110
-rw-r--r--LearnMapKit/ContentView.swift85
-rw-r--r--LearnMapKit/FlighState.swift138
-rw-r--r--LearnMapKit/LearnMapKit.entitlements2
-rw-r--r--LearnMapKit/LearnMapKitApp.swift26
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
- }
}