diff --git a/Cargo.lock b/Cargo.lock index f44e283..cd00cc1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,20 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + [[package]] name = "autocfg" version = "1.0.1" @@ -24,6 +39,12 @@ version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + [[package]] name = "bytes" version = "1.0.1" @@ -50,12 +71,28 @@ checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" dependencies = [ "libc", "num-integer", - "num-traits", - "serde", + "num-traits 0.2.14", + "serde 1.0.126", "time", "winapi", ] +[[package]] +name = "config" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1b9d958c2b1368a663f05538fc1b5975adce1e19f435acceae987aceeeb369" +dependencies = [ + "lazy_static", + "nom", + "rust-ini", + "serde 1.0.126", + "serde-hjson", + "serde_json", + "toml", + "yaml-rust", +] + [[package]] name = "core-foundation" version = "0.9.1" @@ -77,10 +114,22 @@ name = "dsn-visualizer" version = "0.1.0" dependencies = [ "chrono", + "config", "reqwest", + "rpi-led-matrix", + "serde 1.0.126", "xml-rs", ] +[[package]] +name = "embedded-graphics" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40a69991ceb896bd4810a0cf2bcc46fc94b7860573c71f965d8e5b3d66942fed" +dependencies = [ + "byteorder", +] + [[package]] name = "encoding_rs" version = "0.8.28" @@ -170,6 +219,12 @@ dependencies = [ "slab", ] +[[package]] +name = "gcc" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" + [[package]] name = "getrandom" version = "0.2.3" @@ -334,12 +389,31 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lexical-core" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" +dependencies = [ + "arrayvec", + "bitflags", + "cfg-if", + "ryu", + "static_assertions", +] + [[package]] name = "libc" version = "0.2.96" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5600b4e6efc5421841a2138a6b082e07fe12f9aaa12783d50e5d13325b26b4fc" +[[package]] +name = "linked-hash-map" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" + [[package]] name = "log" version = "0.4.14" @@ -407,6 +481,17 @@ dependencies = [ "tempfile", ] +[[package]] +name = "nom" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" +dependencies = [ + "lexical-core", + "memchr", + "version_check", +] + [[package]] name = "ntapi" version = "0.3.6" @@ -423,7 +508,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ "autocfg", - "num-traits", + "num-traits 0.2.14", +] + +[[package]] +name = "num-traits" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" +dependencies = [ + "num-traits 0.2.14", ] [[package]] @@ -581,6 +675,23 @@ dependencies = [ "bitflags", ] +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + [[package]] name = "remove_dir_all" version = "0.5.3" @@ -613,7 +724,7 @@ dependencies = [ "native-tls", "percent-encoding", "pin-project-lite", - "serde", + "serde 1.0.126", "serde_urlencoded", "tokio", "tokio-native-tls", @@ -624,6 +735,23 @@ dependencies = [ "winreg", ] +[[package]] +name = "rpi-led-matrix" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b27442bb974a0fa23b9e6d630490679c3020ac1037c229c666e144d09d883b5" +dependencies = [ + "embedded-graphics", + "gcc", + "libc", +] + +[[package]] +name = "rust-ini" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2" + [[package]] name = "ryu" version = "1.0.5" @@ -663,11 +791,43 @@ dependencies = [ "libc", ] +[[package]] +name = "serde" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" + [[package]] name = "serde" version = "1.0.126" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-hjson" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a3a4e0ea8a88553209f6cc6cfe8724ecad22e1acf372793c27d995290fe74f8" +dependencies = [ + "lazy_static", + "num-traits 0.1.43", + "regex", + "serde 0.8.23", +] + +[[package]] +name = "serde_derive" +version = "1.0.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "serde_json" @@ -677,7 +837,7 @@ checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" dependencies = [ "itoa", "ryu", - "serde", + "serde 1.0.126", ] [[package]] @@ -689,7 +849,7 @@ dependencies = [ "form_urlencoded", "itoa", "ryu", - "serde", + "serde 1.0.126", ] [[package]] @@ -708,6 +868,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "syn" version = "1.0.73" @@ -798,6 +964,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde 1.0.126", +] + [[package]] name = "tower-service" version = "0.3.1" @@ -872,6 +1047,12 @@ version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "025ce40a007e1907e58d5bc1a594def78e5573bb0b1160bc389634e8f12e4faa" +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + [[package]] name = "want" version = "0.3.0" @@ -895,7 +1076,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd" dependencies = [ "cfg-if", - "serde", + "serde 1.0.126", "serde_json", "wasm-bindgen-macro", ] @@ -1002,3 +1183,12 @@ name = "xml-rs" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a" + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] diff --git a/Cargo.toml b/Cargo.toml index c376d21..4f328ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,4 +9,7 @@ edition = "2018" [dependencies] reqwest = {version = "0.11", features=["blocking"]} chrono = {version = "0.4.19", features=["serde"]} -xml-rs = "0.8.3" \ No newline at end of file +xml-rs = "0.8.3" +config = "0.11.0" +serde = {version = "1.0", features=["derive"]} +rpi-led-matrix = "0.2.2" \ No newline at end of file diff --git a/config.toml b/config.toml new file mode 100644 index 0000000..f4c0784 --- /dev/null +++ b/config.toml @@ -0,0 +1,3 @@ +dsn_address = "https://eyes.nasa.gov/dsn/data/dsn.xml" +polling_rate = 5 +spacecraft = [] \ No newline at end of file diff --git a/src/config/mod.rs b/src/config/mod.rs new file mode 100644 index 0000000..8b678c3 --- /dev/null +++ b/src/config/mod.rs @@ -0,0 +1,24 @@ +use serde::Deserialize; +use config::{Config, ConfigError, File}; + +#[derive(Debug, Deserialize, Clone)] +pub struct SpacecraftConfig { + pub spacecraft_name: String, + pub spacecraft_id: u64, + pub color: (u8, u8, u8) +} + +#[derive(Debug, Deserialize, Clone)] +pub struct VisualizerConfig { + pub dsn_address: String, + pub polling_rate: u64, + pub spacecraft: Vec +} + +impl VisualizerConfig { + pub fn new(config_path: &str) -> Result { + let mut cfg = Config::new(); + cfg.merge(File::with_name(config_path))?; + cfg.try_into() + } +} diff --git a/src/dsn/error.rs b/src/dsn/error.rs new file mode 100644 index 0000000..b1fdf9a --- /dev/null +++ b/src/dsn/error.rs @@ -0,0 +1,75 @@ +use std::num::{ParseFloatError, ParseIntError}; +use std::str::ParseBoolError; + +#[derive(Debug)] +pub enum ParseError { + AttrMissing, + ParseIntErr(ParseIntError), + ParseFloatErr(ParseFloatError), + ParseBoolErr(ParseBoolError), + ParseChronoErr(chrono::ParseError), +} + +impl From for ParseError { + fn from(error: ParseIntError) -> Self { + ParseError::ParseIntErr(error) + } +} + +impl From for ParseError { + fn from(error: ParseFloatError) -> Self { + ParseError::ParseFloatErr(error) + } +} + +impl From for ParseError { + fn from(error: ParseBoolError) -> Self { + ParseError::ParseBoolErr(error) + } +} + +impl From for ParseError { + fn from(error: chrono::ParseError) -> Self { + ParseError::ParseChronoErr(error) + } +} + +impl std::fmt::Display for ParseError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ParseError::AttrMissing => write!(f, "Attr missing"), + ParseError::ParseIntErr(e) => write!(f, "Int parse error: {}", e), + ParseError::ParseFloatErr(e) => write!(f, "Int parse error: {}", e), + ParseError::ParseBoolErr(e) => write!(f, "Bool parse error: {}", e), + ParseError::ParseChronoErr(e) => write!(f, "Chrono parse error: {}", e), + } + } +} + +#[derive(Debug)] +pub enum DSNError { + ParseErr(ParseError), + ReqwestErr(reqwest::Error) +} + +impl From for DSNError { + fn from(err: ParseError) -> Self { + DSNError::ParseErr(err) + } +} + +impl From for DSNError { + fn from(err: reqwest::Error) -> Self { + DSNError::ReqwestErr(err) + } +} + +impl std::fmt::Display for DSNError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + DSNError::ParseErr(e) => write!(f, "Req Parse Error: {}", e), + DSNError::ReqwestErr(e) => write!(f, "Reqwest Error: {}", e) + } + } +} + diff --git a/src/dsn/mod.rs b/src/dsn/mod.rs index e50579d..d1dffb4 100644 --- a/src/dsn/mod.rs +++ b/src/dsn/mod.rs @@ -1,10 +1,40 @@ -use crate::dsn::models::{Dish, ParseError, Signal, Station, Target}; +use std::collections::HashMap; use std::convert::TryFrom; use std::io::BufReader; -use xml::reader::XmlEvent; +use std::time::{SystemTime, UNIX_EPOCH}; + +use reqwest::blocking::Client; use xml::EventReader; +use xml::reader::XmlEvent; + +use error::ParseError; + +use crate::dsn::models::{Dish, Signal, Station, Target}; +use crate::dsn::error::DSNError; pub mod models; +pub mod error; + +pub fn dsn_request(client: &Client, dsn_api_url: &str) -> Result, DSNError> { + let mut params = HashMap::new(); + let timestamp = (SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_millis() + / 5000) as u64; + + params.insert("r", timestamp); + + let resp = client + .get(dsn_api_url) + .query(¶ms) + .send()? + .text()?; + + let file = BufReader::new(resp.as_bytes()); + + Ok(parse_dsn_resp(file)?) +} pub fn parse_dsn_resp(reader: BufReader) -> Result, ParseError> where diff --git a/src/dsn/models.rs b/src/dsn/models.rs index 939aece..9c3dad5 100644 --- a/src/dsn/models.rs +++ b/src/dsn/models.rs @@ -1,42 +1,9 @@ use std::convert::TryFrom; -use std::num::{ParseFloatError, ParseIntError}; -use std::str::ParseBoolError; use chrono::{DateTime, Utc}; use xml::attribute::OwnedAttribute; -#[derive(Clone, Debug)] -pub enum ParseError { - AttrMissing, - AttrParseInt(ParseIntError), - AttrParseFloat(ParseFloatError), - AttrParseBool(ParseBoolError), - AttrParseChrono(chrono::ParseError), -} - -impl From for ParseError { - fn from(error: ParseIntError) -> Self { - ParseError::AttrParseInt(error) - } -} - -impl From for ParseError { - fn from(error: ParseFloatError) -> Self { - ParseError::AttrParseFloat(error) - } -} - -impl From for ParseError { - fn from(error: ParseBoolError) -> Self { - ParseError::AttrParseBool(error) - } -} - -impl From for ParseError { - fn from(error: chrono::ParseError) -> Self { - ParseError::AttrParseChrono(error) - } -} +use crate::dsn::error::ParseError; fn get_attr(attrs: &[OwnedAttribute], name: &str) -> Result { attrs diff --git a/src/main.rs b/src/main.rs index ab051db..fa2142b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,35 +1,45 @@ -use crate::dsn::parse_dsn_resp; +use crate::dsn::dsn_request; use reqwest::blocking::Client; -use std::collections::HashMap; -use std::io::BufReader; -use std::time::{SystemTime, UNIX_EPOCH}; +use crate::config::VisualizerConfig; +use std::sync::mpsc; +use std::time::Duration; +use crate::dsn::models::Station; mod dsn; +mod config; -fn main() { +fn dsn_thread(config: VisualizerConfig, tx: mpsc::Sender>) { let client = Client::new(); + let sleep_duration = Duration::from_secs(config.polling_rate); - let mut params = HashMap::new(); - let timestamp = (SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_millis() - / 5000) as u64; - params.insert("r", timestamp); + loop { + match dsn_request(&client, &config.dsn_address) { + Ok(stations) => { + if tx.send(stations).is_err() { + break; + } + } + Err(e) => { + println!("Unable to fetch DSN status: {}", e) + } + } - let resp = client - .get("https://eyes.nasa.gov/dsn/data/dsn.xml") - .query(¶ms) - .send() - .unwrap() - .text() - .unwrap(); - - let file = BufReader::new(resp.as_bytes()); - - let stations = parse_dsn_resp(file).unwrap(); - - for station in stations { - println!("Station: {:?}\n Dishes: {:?}", station.name, station.dishes) + std::thread::sleep(sleep_duration); } } + + +fn main() { + let (tx,rx) = mpsc::channel::>(); + let config = VisualizerConfig::new("config.toml").unwrap(); + + std::thread::spawn(move || dsn_thread(config, tx)); + + loop { + let stations = rx.recv().unwrap(); + for station in stations { + println!("Station: {:?}\n Dishes: {:?}", station.name, station.dishes) + } + } + +}