flight_tracker/
tracker.rs1use adsb::*;
2use std::collections::HashMap;
3use std::time::{Duration, SystemTime};
4use MessageKind::*;
5
6#[derive(Debug, Clone)]
8pub struct Aircraft {
9 pub icao_address: ICAOAddress,
11 pub callsign: Option<String>,
13 pub altitude: Option<u16>,
15 pub heading: Option<f64>,
17 pub ground_speed: Option<f64>,
19 pub vertical_rate: Option<i16>,
21 pub latitude: Option<f64>,
23 pub longitude: Option<f64>,
25 pub vertical_rate_source: Option<VerticalRateSource>,
27 pub last_seen: SystemTime,
29 pub last_squawk: Option<Squawk>,
31 last_cpr_even: Option<CPRFrame>,
32 last_cpr_odd: Option<CPRFrame>,
33}
34
35impl Aircraft {
36 fn new(icao_address: ICAOAddress) -> Self {
37 Aircraft {
38 icao_address,
39 callsign: None,
40 altitude: None,
41 heading: None,
42 ground_speed: None,
43 vertical_rate: None,
44 latitude: None,
45 longitude: None,
46 vertical_rate_source: None,
47 last_seen: SystemTime::now(),
48 last_cpr_even: None,
49 last_cpr_odd: None,
50 last_squawk: None,
51 }
52 }
53
54 fn update_position(&mut self, cpr_frame: CPRFrame) {
55 let last_parity = cpr_frame.parity.clone();
56 match last_parity {
57 Parity::Even => {
58 self.last_cpr_even = Some(cpr_frame);
59 }
60 Parity::Odd => {
61 self.last_cpr_odd = Some(cpr_frame);
62 }
63 }
64 if let (Some(even), Some(odd)) = (&self.last_cpr_even, &self.last_cpr_odd) {
65 let position = match last_parity {
66 Parity::Even => cpr::get_position((odd, even)),
67 Parity::Odd => cpr::get_position((even, odd)),
68 };
69 if let Some(Position {
70 latitude,
71 longitude,
72 }) = position
73 {
74 self.latitude = Some(latitude);
75 self.longitude = Some(longitude);
76 }
77 }
78 }
79}
80
81#[derive(Default)]
83pub struct Tracker {
84 map: HashMap<ICAOAddress, Aircraft>,
85}
86
87impl Tracker {
88 pub fn new() -> Self {
90 Tracker::default()
91 }
92
93 pub fn update_with_avr(&mut self, frame: &str) -> Result<(), adsb::ParserError> {
95 let (message, _) = adsb::parse_avr(frame)?;
96 self.update_with_message(message);
97 Ok(())
98 }
99
100 pub fn update_with_binary(&mut self, frame: &[u8]) -> Result<(), adsb::ParserError> {
102 let (message, _) = adsb::parse_binary(frame)?;
103 self.update_with_message(message);
104 Ok(())
105 }
106
107 fn update_with_message(&mut self, message: Message) {
108 match message {
109 Message {
110 kind: ADSBMessage {
111 icao_address, kind, ..
112 },
113 ..
114 } => self.update_with_adsb_message(icao_address, kind),
115 Message {
116 kind: ModeSMessage { icao_address, kind },
117 ..
118 } => self.update_with_mode_s_message(icao_address, kind),
119 _ => (),
120 };
121 }
122
123 fn update_with_adsb_message(&mut self, icao_address: ICAOAddress, kind: ADSBMessageKind) {
124 use ADSBMessageKind::*;
125
126 let aircraft = self.get_or_create_aircraft(icao_address);
127
128 match kind {
129 AircraftIdentification { callsign, .. } => {
130 aircraft.callsign = Some(callsign.trim().to_string());
131 }
132 AirbornePosition {
133 altitude,
134 cpr_frame,
135 } => {
136 aircraft.altitude = Some(altitude);
137 aircraft.update_position(cpr_frame);
138 }
139 AirborneVelocity {
140 heading,
141 ground_speed,
142 vertical_rate,
143 vertical_rate_source,
144 } => {
145 aircraft.heading = Some(heading);
146 aircraft.ground_speed = Some(ground_speed);
147 aircraft.vertical_rate = Some(vertical_rate);
148 aircraft.vertical_rate_source = Some(vertical_rate_source);
149 }
150 }
151
152 aircraft.last_seen = SystemTime::now();
153 }
154
155 fn update_with_mode_s_message(&mut self, icao_address: ICAOAddress, kind: ModeSMessageKind) {
156 use ModeSMessageKind::*;
157
158 let aircraft = self.get_or_create_aircraft(icao_address);
159
160 match kind {
161 SurveillanceIdentity { squawk } => {
162 aircraft.last_squawk = Some(squawk);
163 }
164 }
165
166 aircraft.last_seen = SystemTime::now();
167 }
168
169 fn get_or_create_aircraft(&mut self, icao_address: ICAOAddress) -> &mut Aircraft {
170 self.map
171 .entry(icao_address)
172 .or_insert_with(|| Aircraft::new(icao_address))
173 }
174
175 pub fn get_current_aircraft(&self, interval: &Duration) -> Vec<&Aircraft> {
177 self.map
178 .values()
179 .filter(|a| match a.last_seen.elapsed() {
180 Ok(elapsed) => elapsed < *interval,
181 Err(_) => false,
182 })
183 .collect()
184 }
185
186 pub fn get_all_aircraft(&self) -> Vec<&Aircraft> {
188 self.map.values().collect()
189 }
190}