commit 89a7457aab9f8d5c44d110f988cbf2e76b048a59
Author: MTRNord <mtrnord1@gmail.com>
Date: Thu, 5 Aug 2021 02:16:51 +0200
initial commit
Diffstat:
6 files changed, 259 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,2 @@
+/target
+Cargo.lock
diff --git a/Cargo.toml b/Cargo.toml
@@ -0,0 +1,20 @@
+cargo-features = ["edition2021"]
+
+[package]
+name = "xplane-datamonitor"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+crate-type = ["cdylib"]
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+xplm = "0.3.1"
+anyhow = "1.0.42"
+thiserror = "1.0.26"
+tokio = { version = "1", features = ["full"] }
+
+[profile.release]
+lto = true
+\ No newline at end of file
diff --git a/src/energy.rs b/src/energy.rs
@@ -0,0 +1,58 @@
+use std::{
+ fmt::Display,
+ sync::{Arc, RwLock},
+};
+
+use xplm::data::{borrowed::DataRef, ArrayRead, DataRead, ReadWrite};
+
+use crate::error::Error;
+
+pub(crate) struct EnergyRefs {
+ pub(crate) gpu_on: DataRef<bool, ReadWrite>,
+ pub(crate) battery: DataRef<[i32], ReadWrite>,
+}
+
+unsafe impl Send for EnergyRefs {}
+unsafe impl Sync for EnergyRefs {}
+
+#[derive(Clone)]
+pub(crate) struct Energy {
+ inner: Arc<RwLock<EnergyRefs>>,
+}
+
+impl Energy {
+ pub(crate) fn new() -> Result<Self, Error> {
+ Ok(Self {
+ inner: Arc::new(RwLock::new(EnergyRefs {
+ gpu_on: DataRef::find("sim/cockpit/electrical/gpu_on")?.writeable()?,
+ battery: DataRef::find("sim/cockpit2/electrical/battery_on")?.writeable()?,
+ })),
+ })
+ }
+
+ pub(crate) fn gpu_on(&self) -> Result<bool, Error> {
+ let lock = self.inner.read().or(Err(Error::UnableToGetLock))?;
+ Ok(lock.gpu_on.get())
+ }
+
+ pub(crate) fn battery_on(&self) -> Result<bool, Error> {
+ let lock = self.inner.read().or(Err(Error::UnableToGetLock))?;
+ Ok(lock.battery.as_vec().contains(&1))
+ }
+}
+
+impl Display for Energy {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let lock = self.inner.read();
+ if let Ok(lock) = lock {
+ write!(
+ f,
+ "GPU enabled: {}, Battery enabled: {}",
+ lock.gpu_on.get(),
+ lock.battery.as_vec().contains(&1),
+ )
+ } else {
+ Ok(())
+ }
+ }
+}
diff --git a/src/error.rs b/src/error.rs
@@ -0,0 +1,9 @@
+use thiserror::Error as ThisError;
+
+#[derive(ThisError, Debug)]
+pub(crate) enum Error {
+ #[error(transparent)]
+ FindError(#[from] xplm::data::borrowed::FindError),
+ #[error("Unable to get lock")]
+ UnableToGetLock,
+}
diff --git a/src/lib.rs b/src/lib.rs
@@ -0,0 +1,112 @@
+use std::{
+ sync::{
+ atomic::{AtomicBool, Ordering},
+ Arc, RwLock,
+ },
+ thread::JoinHandle,
+};
+#[deny(unused_imports)]
+#[deny(missing_docs)]
+use std::{thread, time};
+use tokio::runtime::Runtime;
+use xplm::{
+ debug,
+ plugin::{Plugin, PluginInfo},
+ xplane_plugin,
+};
+
+use crate::location::Location;
+use crate::{energy::Energy, error::Error};
+
+mod energy;
+mod error;
+mod location;
+
+#[derive(Clone)]
+struct DataMonitorPlugin {
+ location: Location,
+ energy: Energy,
+ thread: Arc<RwLock<Option<JoinHandle<()>>>>,
+ stopped: Arc<AtomicBool>,
+}
+
+impl DataMonitorPlugin {
+ pub(crate) fn start(&self) {
+ debug("[DATAMONITOR] starting\n");
+ let self_clone = self.clone();
+ let thread = thread::spawn(move || {
+ let delay = time::Duration::from_secs(5);
+ {
+ debug(format!("[DATAMONITOR] {}\n", self_clone.location));
+ };
+ let rt = Runtime::new().unwrap();
+ loop {
+ // Do stuff
+ if self_clone.stopped.load(Ordering::Relaxed) {
+ break;
+ }
+
+ let current_location = self_clone.location.clone();
+ let current_energy = self_clone.energy.clone();
+ rt.spawn(async move {
+ // Do stuff with location
+ if current_energy.battery_on().unwrap() || current_energy.gpu_on().unwrap() {
+ debug(format!("[DATAMONITOR] {}\n", current_location));
+ debug(format!("[DATAMONITOR] {}\n", current_energy));
+ }
+ });
+ thread::sleep(delay);
+ }
+ });
+ let mut lock = self.thread.write().unwrap();
+ *lock = Some(thread);
+ }
+}
+
+impl Plugin for DataMonitorPlugin {
+ type Error = Error;
+
+ fn start() -> Result<Self, Self::Error> {
+ let location = Location::new();
+ if let Err(ref e) = location {
+ debug(format!("[DATAMONITOR][ERROR] Location init: {:?}\n", e));
+ }
+ let energy = Energy::new();
+ if let Err(ref e) = energy {
+ debug(format!("[DATAMONITOR][ERROR] Energy init: {:?}\n", e));
+ }
+ let plugin = DataMonitorPlugin {
+ location: location.unwrap(),
+ energy: energy.unwrap(),
+ thread: Arc::new(RwLock::new(None)),
+ stopped: Arc::new(AtomicBool::new(false)),
+ };
+ Ok(plugin)
+ }
+ fn enable(&mut self) -> Result<(), Self::Error> {
+ self.start();
+ Ok(())
+ }
+ fn disable(&mut self) {
+ debug("[DATAMONITOR][INFO] Stopping threads\n");
+ self.stopped.swap(true, Ordering::Release);
+ let mut lock = self.thread.write().unwrap();
+ let thread = std::mem::replace(&mut *lock, None);
+ if let Some(thread) = thread {
+ thread.join().unwrap();
+ debug("[DATAMONITOR][INFO] Stopped threads\n");
+ }
+ }
+
+ fn info(&self) -> xplm::plugin::PluginInfo {
+ PluginInfo {
+ name: String::from("Datamonitor"),
+ signature: String::from("dev.nordgedanken.datamonitor"),
+ description: String::from(
+ "Gets certain datarefs to display in a grafana for review of flights.",
+ ),
+ }
+ }
+}
+
+xplane_plugin!(DataMonitorPlugin);
diff --git a/src/location.rs b/src/location.rs
@@ -0,0 +1,57 @@
+use std::{
+ fmt::Display,
+ sync::{Arc, RwLock},
+};
+
+use xplm::data::{borrowed::DataRef, DataRead, ReadOnly};
+
+use crate::error::Error;
+
+pub(crate) struct LocationRefs {
+ pub(crate) latitude: DataRef<f64, ReadOnly>,
+ pub(crate) longitude: DataRef<f64, ReadOnly>,
+}
+
+unsafe impl Send for LocationRefs {}
+unsafe impl Sync for LocationRefs {}
+
+#[derive(Clone)]
+pub(crate) struct Location {
+ inner: Arc<RwLock<LocationRefs>>,
+}
+
+impl Location {
+ pub(crate) fn new() -> Result<Self, Error> {
+ Ok(Self {
+ inner: Arc::new(RwLock::new(LocationRefs {
+ latitude: DataRef::find("sim/flightmodel/position/latitude")?,
+ longitude: DataRef::find("sim/flightmodel/position/longitude")?,
+ })),
+ })
+ }
+
+ pub(crate) fn lat(&self) -> Result<f64, Error> {
+ let lock = self.inner.read().or(Err(Error::UnableToGetLock))?;
+ Ok(lock.latitude.get())
+ }
+ pub(crate) fn lon(&self) -> Result<f64, Error> {
+ let lock = self.inner.read().or(Err(Error::UnableToGetLock))?;
+ Ok(lock.longitude.get())
+ }
+}
+
+impl Display for Location {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let lock = self.inner.read();
+ if let Ok(lock) = lock {
+ write!(
+ f,
+ "Latitude: {}, Longitude: {}",
+ lock.latitude.get(),
+ lock.longitude.get()
+ )
+ } else {
+ Ok(())
+ }
+ }
+}