Skip to content

Commit

Permalink
add subcommands (#104)
Browse files Browse the repository at this point in the history
  • Loading branch information
zacharyburnett authored Aug 16, 2023
1 parent 77ecb4d commit 74bbb09
Show file tree
Hide file tree
Showing 10 changed files with 130 additions and 22 deletions.
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ The program is designed to be run during a flight and display information in a t
Run your executable from the terminal with the path to your configuration file:
```shell
./packetraven_Windows.exe examples/example_1.yaml
./packetraven_Windows.exe run examples/example_1.yaml
```
[Instructions for creating a configuration file can be found in the documentation](https://packetraven.readthedocs.io/en/latest/configuration.html).
Expand All @@ -61,3 +61,13 @@ and the up and down arrow keys change the current plot (or scroll through log me

To quit, press `q` or `Esc`.

### Prediction

You can run the `predict` subcommand to retrieve a prediction:

```shell
./packetraven_Windows.exe predict "2023-08-16T10:00:00" -- -79 39 5 30000 9
```

> **Note**\
> Negative values must be prepended with `-- `, e.g. `-- -79`.
6 changes: 3 additions & 3 deletions src/configuration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ fn default_name() -> String {
String::from("unnamed_flight")
}

#[derive(serde::Deserialize, Clone)]
#[derive(serde::Deserialize, Clone, Default, serde::Serialize)]
pub struct RunConfiguration {
#[serde(default = "default_name")]
pub name: String,
Expand All @@ -23,7 +23,7 @@ fn default_interval() -> chrono::Duration {
}

#[serde_with::serde_as]
#[derive(PartialEq, Debug, serde::Deserialize, Clone)]
#[derive(PartialEq, Debug, serde::Deserialize, Clone, serde::Serialize)]
pub struct TimeConfiguration {
#[serde(default)]
#[serde(with = "crate::utilities::optional_local_datetime_string")]
Expand All @@ -46,7 +46,7 @@ impl Default for TimeConfiguration {
}
}

#[derive(Default, serde::Deserialize, PartialEq, Debug, Clone)]
#[derive(Default, serde::Deserialize, PartialEq, Debug, Clone, serde::Serialize)]
pub struct ConnectionConfiguration {
pub text: Option<Vec<crate::connection::text::TextStream>>,
#[cfg(feature = "sondehub")]
Expand Down
8 changes: 4 additions & 4 deletions src/configuration/prediction.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use serde_with::serde_as;

#[derive(serde::Deserialize, Clone)]
#[derive(serde::Deserialize, Clone, serde::Serialize)]
#[serde(untagged)]
pub enum PredictionConfiguration {
Single(Prediction),
Expand All @@ -14,7 +14,7 @@ fn default_name() -> String {
String::from("prediction")
}

#[derive(serde::Deserialize, PartialEq, Debug, Clone)]
#[derive(serde::Deserialize, PartialEq, Debug, Clone, serde::Serialize)]
pub struct Prediction {
pub start: crate::location::Location,
pub profile: StandardProfile,
Expand Down Expand Up @@ -63,7 +63,7 @@ fn default_descent_only() -> bool {
false
}

#[derive(serde::Deserialize, PartialEq, Debug, Clone)]
#[derive(serde::Deserialize, PartialEq, Debug, Clone, serde::Serialize)]
pub struct StandardProfile {
pub ascent_rate: f64,
pub burst_altitude: f64,
Expand All @@ -74,7 +74,7 @@ pub struct StandardProfile {
}

#[serde_as]
#[derive(serde::Deserialize, PartialEq, Debug, Clone)]
#[derive(serde::Deserialize, PartialEq, Debug, Clone, serde::Serialize)]
pub struct FloatProfile {
pub altitude: f64,
pub uncertainty: Option<f64>,
Expand Down
2 changes: 1 addition & 1 deletion src/connection/aprs_fi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ lazy_static::lazy_static! {
static ref MINIMUM_ACCESS_INTERVAL: chrono::Duration = chrono::Duration::seconds(10);
}

#[derive(serde::Deserialize, Debug, PartialEq, Clone)]
#[derive(serde::Deserialize, Debug, PartialEq, Clone, serde::Serialize)]
pub struct AprsFiQuery {
pub api_key: String,
pub callsigns: Option<Vec<String>>,
Expand Down
2 changes: 1 addition & 1 deletion src/connection/postgres.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use chrono::TimeZone;

#[derive(serde::Deserialize, Debug, PartialEq, Clone)]
#[derive(serde::Deserialize, Debug, PartialEq, Clone, serde::Serialize)]
pub struct DatabaseCredentials {
pub hostname: String,
pub port: u32,
Expand Down
2 changes: 1 addition & 1 deletion src/connection/sondehub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ lazy_static::lazy_static! {
static ref MINIMUM_ACCESS_INTERVAL: chrono::Duration = chrono::Duration::seconds(10);
}

#[derive(serde::Deserialize, Debug, PartialEq, Clone, Default)]
#[derive(serde::Deserialize, Debug, PartialEq, Clone, Default, serde::Serialize)]
pub struct SondeHubQuery {
pub start: Option<chrono::DateTime<chrono::Local>>,
pub end: Option<chrono::DateTime<chrono::Local>>,
Expand Down
4 changes: 2 additions & 2 deletions src/connection/text/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::io::prelude::BufRead;

use chrono::{TimeZone, Timelike};

#[derive(serde::Deserialize, Debug, PartialEq, Clone)]
#[derive(serde::Deserialize, Debug, PartialEq, Clone, serde::Serialize)]
pub struct AprsTextFile {
pub path: String,
pub callsigns: Option<Vec<String>>,
Expand Down Expand Up @@ -134,7 +134,7 @@ impl AprsTextFile {
}
}

#[derive(serde::Deserialize, Debug, PartialEq, Clone)]
#[derive(serde::Deserialize, Debug, PartialEq, Clone, serde::Serialize)]
pub struct GeoJsonFile {
pub path: String,
}
Expand Down
2 changes: 1 addition & 1 deletion src/connection/text/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ pub mod file;
#[cfg(feature = "serial")]
pub mod serial;

#[derive(serde::Deserialize, Debug, PartialEq, Clone)]
#[derive(serde::Deserialize, Debug, PartialEq, Clone, serde::Serialize)]
#[serde(untagged)]
pub enum TextStream {
AprsTextFile(file::AprsTextFile),
Expand Down
2 changes: 1 addition & 1 deletion src/connection/text/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ lazy_static::lazy_static! {
static ref DEFAULT_BAUD_RATE: u32 = 9600;
}

#[derive(serde::Deserialize, Debug, PartialEq, Clone)]
#[derive(serde::Deserialize, Debug, PartialEq, Clone, serde::Serialize)]
pub struct AprsSerial {
#[serde(default = "first_available_port")]
pub port: String,
Expand Down
112 changes: 105 additions & 7 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,115 @@ lazy_static::lazy_static! {
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct PacketravenCommand {
// configuration file to read
config_file: std::path::PathBuf,
#[command(subcommand)]
command: Command,
}

#[derive(clap::Subcommand)]
enum Command {
/// run program from configuration
Run {
/// file path to configuration
config_file: std::path::PathBuf,
},
/// retrieve a balloon prediction from the given API
Predict {
/// start time
time: chrono::NaiveDateTime,
/// start longitude
longitude: f64,
/// start latitude
latitude: f64,
/// start altitude
#[arg(short, long)]
altitude: Option<f64>,
/// expected average ascent rate
ascent_rate: f64,
/// expected burst altitude
burst_altitude: f64,
/// descent rate at sea level
sea_level_descent_rate: f64,
/// desired float altitude
#[arg(long)]
float_altitude: Option<f64>,
/// desired float duration in seconds
#[arg(long)]
float_duration: Option<f64>,
},
/// write an empty configuration file
Write {
/// file path to configuration
filename: std::path::PathBuf,
},
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
let arguments = PacketravenCommand::parse();

let configuration_file = std::fs::File::open(arguments.config_file).unwrap();
let configuration: crate::configuration::RunConfiguration =
serde_yaml::from_reader(configuration_file).expect("error reading configuration");
match arguments.command {
Command::Run { config_file } => {
let file = std::fs::File::open(config_file).unwrap();
let configuration: crate::configuration::RunConfiguration =
serde_yaml::from_reader(file).expect("error reading configuration");

tui::run(configuration, *LOG_LEVEL)?;
Ok(())
}
Command::Predict {
time,
longitude,
latitude,
altitude,
ascent_rate,
burst_altitude,
sea_level_descent_rate,
float_altitude,
float_duration,
} => {
let start = location::Location {
time: time.and_local_timezone(chrono::Local).unwrap(),
coord: geo::coord! {x:longitude,y:latitude},
altitude,
};
let profile = prediction::FlightProfile::new(
ascent_rate,
float_altitude,
match float_duration {
Some(seconds) => Some(chrono::Duration::seconds(seconds as i64)),
None => None,
},
None,
burst_altitude,
sea_level_descent_rate,
);

let query = prediction::tawhiri::TawhiriQuery::new(
&start, &profile, None, None, None, false, None,
);

match query.retrieve_prediction() {
Ok(prediction) => {
for location in prediction {
println!(
"{:}, {:.1}, {:.1}, {:.1}",
location.location.time.format("%Y-%m-%d %H:%M:%S"),
location.location.coord.x,
location.location.coord.y,
location.location.altitude.unwrap_or(0.0)
);
}
}
Err(error) => return Err(Box::new(error)),
}

Ok(())
}
Command::Write { filename } => {
let configuration = configuration::RunConfiguration::default();
let file = std::fs::File::create(filename).unwrap();

tui::run(configuration, *LOG_LEVEL)?;
Ok(())
serde_yaml::to_writer(file, &configuration).unwrap();
Ok(())
}
}
}

0 comments on commit 74bbb09

Please sign in to comment.