Skip to content

Commit

Permalink
Refactor to keep track of planes for a while
Browse files Browse the repository at this point in the history
  • Loading branch information
MattBlack85 committed May 24, 2022
1 parent 275e47b commit 9f66e08
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 24 deletions.
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ edition = "2021"

[dependencies]
geo = "0.20.0"
geo-types = "0.7.4"
dialoguer = "0.10.0"
csv = "1.1.6"
serde = {version = "1.0.117", features = ["derive"]}
configparser = "3.0.0"
dirs = "4.0.0"
dirs = "4.0.0"
log = "0.4"
env_logger = "0.9"
chrono = "0.4"
103 changes: 103 additions & 0 deletions src/aero/db.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
use crate::Airdata;
use geo::point;
use geo_types::Point;
use log::debug;
use std::collections::hash_map::Entry;
use std::collections::HashMap;

use chrono::NaiveDateTime;
use geo::prelude::GeodesicDistance;

/// The "database" where data are stored and checked, the DB is a hashmap
/// where the key is the plane number and the value is a vector contaiing
/// Airdata struct containing all plane information.
pub struct Planes {
pub db: HashMap<String, Vec<Airdata>>,
point: Point<f64>,
}

impl Planes {
pub fn new(latitude: String, longitude: String) -> Self {
Self {
db: HashMap::new(),
point: point!(x: longitude.parse::<f64>().unwrap(), y: latitude.parse::<f64>().unwrap()),
}
}

pub fn is_plane_approaching(&mut self, aircraft_address: &String) -> u8 {
// retrieve the data we already have about an aircraft
let aircraft_data: &Vec<Airdata> = self.db.get(aircraft_address).unwrap();
let data_length = aircraft_data.len();

// If we have less than 2 entries we can't yet calculate if the plane is
// getting away/closer from/to us
if data_length < 2 {
return 2;
}

// Build a point in space of the last know coordinates of this aircraft
let airplane = &aircraft_data[data_length - 2];
let old_plane_location = point!(x: airplane.longitude.parse::<f64>().unwrap(), y: airplane.latitude.parse::<f64>().unwrap());

// Build a point in space where the actual aircraft is
let last_data: &Airdata = aircraft_data.last().unwrap();
let actual_plane_location = point!(x: last_data.longitude.parse::<f64>().unwrap(), y: last_data.latitude.parse::<f64>().unwrap());

if self.point.geodesic_distance(&actual_plane_location)
< self.point.geodesic_distance(&old_plane_location)
{
return 0;
} else {
self.db.remove(aircraft_address);
return 1;
}
}

/// Returns true/false if the aircraft id already exists inside the database
pub fn already_seen(&self, aircraft_id: &String) -> bool {
return self.db.contains_key(aircraft_id);
}

pub fn add_plane(&mut self, airplane: Airdata) {
self.db
.insert(airplane.aircraft_address.clone(), vec![airplane]);
}

/// If the aircraft is already in the database new data is appended
/// in the database
pub fn add_data_for_aircraft(&mut self, airplane: Airdata) {
if let Entry::Occupied(mut entry) = self.db.entry(airplane.aircraft_address.to_owned()) {
debug!("Pushing data for {}", &airplane.aircraft_address);
let data = entry.get_mut();
data.push(airplane);
}
}

pub fn check_old_data_too_fresh(&self, airplane: Airdata) -> bool {
let aircraft_data: &Vec<Airdata> = self.db.get(&airplane.aircraft_address).unwrap();
let last_data: &Airdata = aircraft_data.last().unwrap();

let last_data_received = NaiveDateTime::parse_from_str(
&format!("{} {}", &last_data.date_received, &last_data.hour_received),
"%Y/%m/%d %H:%M:%S%.3f",
)
.unwrap();

let new_data_received = NaiveDateTime::parse_from_str(
&format!("{} {}", &airplane.date_received, &airplane.hour_received),
"%Y/%m/%d %H:%M:%S%.3f",
)
.unwrap();
let duration = new_data_received - last_data_received;
debug!(
"Elapsed {} seconds form last time we saw {}",
duration.num_seconds(),
&last_data.aircraft_address,
);
if duration.num_seconds() > 5 {
false
} else {
true
}
}
}
1 change: 1 addition & 0 deletions src/aero/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub mod db;
pub mod structs;
8 changes: 4 additions & 4 deletions src/aero/structs.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use serde::Deserialize;

#[derive(Deserialize)]
#[derive(Deserialize, Clone, Debug)]
pub struct Airdata {
pub msg: String,
pub msg_type: String,
dummy_1: String,
dummy_2: String,
_dummy_1: String,
_dummy_2: String,
pub aircraft_address: String,
dummy_3: String,
_dummy_3: String,
pub date_received: String,
pub hour_received: String,
pub date_written: String,
Expand Down
2 changes: 0 additions & 2 deletions src/airconfig/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use dirs;
static CONFIG_PATH: &'static str = ".config/rnav_alerts/";
static CONFIG_FILENAME: &'static str = "alerts.cfg";


/// Checks if the configuration file exists, if not create it.
pub fn check_config_exists() -> bool {
let full_path = format!(
Expand Down Expand Up @@ -58,7 +57,6 @@ pub fn read_config() -> HashMap<String, HashMap<String, Option<String>>> {
/// is not found on the disk. It will drive the user through some questions
/// building an ini compatible file that will be stored at $HOME/.config/rnav-alerts/alerts.cfg
pub fn setup_config() {

let mut config = String::new();

println!("First, I will ask you about the place that I should monitor\n");
Expand Down
64 changes: 47 additions & 17 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@ use std::net::TcpStream;
use std::error::Error;
use std::str;

use log::{debug, error, info};

mod aero;
mod airconfig;

use aero::db::Planes;
use aero::structs::Airdata;


fn main() -> Result<(), Box<dyn Error>> {
env_logger::init();
if !airconfig::check_config_exists() {
airconfig::setup_config();
}
Expand All @@ -31,11 +34,15 @@ fn main() -> Result<(), Box<dyn Error>> {
.parse::<f64>()
.unwrap();

// This is the place of the listener, from here we base our assumptions about distance
let place = point!(x: longitude.parse::<f64>().unwrap(), y: latitude.parse::<f64>().unwrap());

// Open a TCP stream connection to the socket where CSV data are published by the 1090 program
let mut stream = TcpStream::connect(format!("{}:{}", host, port))?;
let mut planes = Planes::new(latitude, longitude);

loop {
let mut buf = [0; 8192];
let mut buf = [0; 16384];
let bytes = stream.read(&mut buf)?;
let s = str::from_utf8(&buf[0..bytes]).unwrap();

Expand All @@ -46,24 +53,47 @@ fn main() -> Result<(), Box<dyn Error>> {
// let record = result?;
let airdata: Airdata = result?.deserialize(None)?;

let lat = airdata.latitude;
let lon = airdata.longitude;
if airdata.latitude != "" && airdata.longitude != "" {
let address = airdata.aircraft_address.clone();
if planes.already_seen(&address) {
debug!("plane {} already seen, checking if approaching", &address);
debug!("checking if it is too early to append data");

if lat != "" && lon != "" {
let plane = point!(x: lon.parse::<f64>().unwrap(), y: lat.parse::<f64>().unwrap());
let mut distance = place.geodesic_distance(&plane);
if !planes.check_old_data_too_fresh(airdata.clone()) {
debug!("appending data plane {}", &address);
planes.add_data_for_aircraft(airdata.clone());
}

if units == "mi" {
distance = distance * 0.0006213712f64;
} else {
distance = distance / 1000f64;
}
match planes.is_plane_approaching(&address) {
0 => {
let plane = point!(x: airdata.longitude.parse::<f64>().unwrap(), y: airdata.latitude.parse::<f64>().unwrap());
let mut distance = place.geodesic_distance(&plane);

if units == "mi" {
distance = distance * 0.0006213712f64;
} else {
distance = distance / 1000f64;
}

if distance < alerting_distance {
println!(
"The distance between you and the plane {} is {:.3} {}",
airdata.aircraft_address, distance, units
);
if distance < alerting_distance {
info!(
"plane {} is at alerting distance, {:.3} {}",
airdata.aircraft_address, distance, units
);
} else {
info!(
"plane {} is approaching but is not under alerting distance",
&address
);
}
}
1 => debug!("plane {} is getting away from us", &address),
2 => debug!("Not enough data yet to check {}", &address),
_ => error!("Unexpected value"),
}
} else {
// First time we meet an aircraft
planes.add_plane(airdata.clone());
}
}
}
Expand Down

0 comments on commit 9f66e08

Please sign in to comment.