summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Silverstone <daniel.silverstone@codethink.co.uk>2018-05-30 16:20:31 +0100
committerDaniel Silverstone <daniel.silverstone@codethink.co.uk>2018-05-30 16:20:31 +0100
commite44ecc96fb79a3aea3cbabbcf9797fb7b21530c6 (patch)
tree43fb0413b6ae5d6bab02816aa65706087056dd31
parent3a60e93d92659c211b755bae2f71d2cc655111f2 (diff)
downloadcanopied-e44ecc96fb79a3aea3cbabbcf9797fb7b21530c6.tar.bz2
Add derived units
-rw-r--r--definitions/derived.yaml37
-rw-r--r--definitions/units.yaml7
-rw-r--r--src/definitions.rs86
-rw-r--r--src/main.rs6
4 files changed, 134 insertions, 2 deletions
diff --git a/definitions/derived.yaml b/definitions/derived.yaml
new file mode 100644
index 0000000..13b7946
--- /dev/null
+++ b/definitions/derived.yaml
@@ -0,0 +1,37 @@
+# Derived values in Canopied are constructed by means of the raw ECU values
+# generated from raw.yaml and the derived units in units.yaml
+#
+# Each derived value can depend only on raw values and units, and derived values
+# from earlier in this file. This means the result is acyclic.
+#
+# Each derived value has a name, an expression, and a display unit.
+# It is critical that the expression's quantifier and the display unit's
+# quantifier are conformable. E.g. it's acceptable for an expression in mi/hr
+# to be displayed in m/s, but not in Wh/mi. The display unit must be from the
+# units.yaml list and cannot be an expression. If you want a compound unit,
+# then you should add it to units.yaml and use it here.
+
+- id: main_voltage
+ display: volt
+ expr: bms1.battery_voltage * volt
+
+- id: main_current
+ display: amp
+ expr: bms1.battery_current * amp
+
+- id: main_power
+ display: kw
+ expr: main_voltage * main_current
+
+- id: speed
+ display: mph
+ expr: (vmcu1.vehicle_speed / 100) * mph
+
+- id: consumption
+ display: watthourspermile
+ expr: main_power / speed
+
+- id: efficiency
+ display: milesperkwh
+ expr: speed / main_power
+
diff --git a/definitions/units.yaml b/definitions/units.yaml
index 37ad846..aabe9ee 100644
--- a/definitions/units.yaml
+++ b/definitions/units.yaml
@@ -112,3 +112,10 @@
suffix: mi/kWh
expr: mile / (kilowatt * hour)
+- id: milesperhour
+ aliases:
+ - mph
+ - miph
+ suffix: mph
+ expr: mile / hour
+
diff --git a/src/definitions.rs b/src/definitions.rs
index 5a414dd..ea6319a 100644
--- a/src/definitions.rs
+++ b/src/definitions.rs
@@ -1,5 +1,6 @@
use serde_yaml;
+use exprast::*;
use exprparser;
use qexpr;
use qvalue::*;
@@ -222,6 +223,12 @@ impl RawECUEntry {
Some(ret)
}
+
+ pub fn populate_fake_scalars(&self, into: &mut HashMap<String, QValue>) {
+ for resp in &self.response.values {
+ into.insert(format!("{}.{}", self.name, resp.name), QValue::new(1.0));
+ }
+ }
}
pub struct CadencedECUs {
@@ -352,4 +359,83 @@ impl Units {
into.insert(k.clone(), self.qvals[*v].clone());
});
}
+
+ pub fn find(&self, unit: &str) -> Option<QValue> {
+ self.all.get(unit).and_then(|i| Some(self.qvals[*i]))
+ }
+}
+
+#[derive(Debug, Deserialize)]
+struct RawDerived {
+ id: String,
+ display: String,
+ expr: String,
+}
+
+impl RawDerived {
+ fn get_all() -> &'static [RawDerived] {
+ lazy_static! {
+ static ref DEFS: Vec<RawDerived> =
+ serde_yaml::from_slice(include_bytes!("../definitions/derived.yaml")).unwrap();
+ }
+ &DEFS
+ }
+}
+
+pub struct Derived {
+ raw: &'static [RawDerived],
+ expr: Vec<Expression>,
+}
+
+impl Derived {
+ pub fn get() -> &'static Derived {
+ lazy_static! {
+ static ref DEFS: Derived = Derived::new();
+ }
+ &DEFS
+ }
+
+ fn new() -> Derived {
+ let mut symbols = HashMap::new();
+ for ecu in RawECUEntry::get_all() {
+ ecu.populate_fake_scalars(&mut symbols);
+ }
+ let units = Units::get();
+ units.populate(&mut symbols);
+ let raw = RawDerived::get_all();
+ let mut exprs = Vec::new();
+
+ for i in 0..raw.len() {
+ let expr = match exprparser::parse_expression(&raw[i].expr) {
+ Some(e) => e,
+ None => panic!("Unable to parse expression for derived {}", raw[i].id),
+ };
+ let displayunit = units.find(&raw[i].display).expect(&format!(
+ "Unable to find display unit for derived {}",
+ raw[i].id
+ ));
+ if let Some(res) = qexpr::evaluate(&expr, &symbols) {
+ trace!("OK, managed to evaluate expression");
+ if !(res / displayunit).quantifier().is_scalar() {
+ panic!(
+ "Expression for derived {} is not conformable to its display unit",
+ raw[i].id
+ );
+ }
+ symbols.insert(raw[i].id.clone(), res);
+ } else {
+ panic!("Unable to evaluate expression for derived {}", raw[i].id);
+ }
+ exprs.push(expr);
+ }
+
+ Derived {
+ raw: raw,
+ expr: exprs,
+ }
+ }
+
+ pub fn count(&self) -> usize {
+ self.raw.len()
+ }
}
diff --git a/src/main.rs b/src/main.rs
index 319894d..8daac6c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -27,8 +27,8 @@ mod qvalue;
mod types;
use futures::sync::mpsc;
-use std::collections::HashMap;
use std::collections::hash_map::Entry;
+use std::collections::HashMap;
use std::env::args;
use std::sync::Mutex;
use std::time::{Duration, Instant};
@@ -61,9 +61,11 @@ fn main() {
let raw_defs = definitions::RawECUEntry::get_all();
let units = definitions::Units::get();
+ let derived = definitions::Derived::get();
info!("Read {} raw ecu entries", raw_defs.len());
info!("Read {} unit definitions", units.count());
+ info!("Read {} derived definitions", derived.count());
let world = futures::future::lazy(move || {
let args: Vec<String> = args().collect();
@@ -120,7 +122,7 @@ fn main() {
let curmap = current.get_mut().unwrap();
for entry in decoded {
let name = entry.get_name().to_owned();
- if !name.contains(".unused_") {
+ if !name.contains("speed") {
continue;
}
let value = entry.get_value().unwrap();