summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Silverstone <daniel.silverstone@codethink.co.uk>2018-05-30 13:57:34 +0100
committerDaniel Silverstone <daniel.silverstone@codethink.co.uk>2018-05-30 13:57:34 +0100
commit3a60e93d92659c211b755bae2f71d2cc655111f2 (patch)
tree2db750fa40a71831d7447a5f48d81abbbf518aaa
parentbeed129c52f029dd94038a3faf4a5fc69e69e3b7 (diff)
downloadcanopied-3a60e93d92659c211b755bae2f71d2cc655111f2.tar.bz2
Add units loader and some basic units
-rw-r--r--definitions/units.yaml114
-rw-r--r--src/definitions.rs106
-rw-r--r--src/main.rs10
-rw-r--r--src/qvalue.rs4
4 files changed, 223 insertions, 11 deletions
diff --git a/definitions/units.yaml b/definitions/units.yaml
new file mode 100644
index 0000000..37ad846
--- /dev/null
+++ b/definitions/units.yaml
@@ -0,0 +1,114 @@
+# Units which are used by Canopied
+#
+# Units have a name, a suffix (for display), and an expression for the unit.
+#
+# Units get to derive from other units, and from the raw units from the
+# internal quantified values system in Canopied.
+#
+# The raw units are each quantified values whose value is 1 and whose quantity
+# is one of voltage, current, temperature, distance, and time.
+#
+# Units may not depend on units which depend on themselves. Instead the
+# dependencies between unit definitions need to be acyclic. During load, units
+# will be checked in-order and thus may only depend on units defined before them
+# in this file.
+
+# The basic units wrappering the raw units
+- id: volt
+ aliases:
+ - volts
+ - voltage
+ suffix: V
+ expr: raw.voltage
+- id: amp
+ aliases:
+ - amps
+ - current
+ suffix: A
+ expr: raw.current
+- id: celsius
+ aliases:
+ - kelvin
+ - centigrade
+ - temp
+ - temperature
+ - c
+ - degc
+ - degree
+ - degrees
+ suffix: °C
+ expr: raw.temperature
+- id: metre
+ aliases:
+ - meter
+ - distance
+ - m
+ suffix: m
+ expr: raw.distance
+- id: second
+ aliases:
+ - seconds
+ - sec
+ - secs
+ - s
+ suffix: s
+ expr: raw.time
+
+# Useful scalar variants of those units
+- id: kilometre
+ aliases:
+ - kilometer
+ - km
+ - kms
+ suffix: km
+ expr: 1000 * m
+- id: mile
+ aliases:
+ - miles
+ - mi
+ suffix: mi
+ expr: 1609.344 * m
+
+- id: minute
+ aliases:
+ - minutes
+ - min
+ - mins
+ suffix: min
+ expr: 60 * s
+- id: hour
+ aliases:
+ - hours
+ - hr
+ - hrs
+ suffix: h
+ expr: 60 * min
+
+# Basic derived units, and scalar variants thereof
+- id: watt
+ aliases:
+ - watts
+ - w
+ - power
+ suffix: W
+ expr: volt * amp
+- id: kilowatt
+ aliases:
+ - kilowatts
+ - kw
+ suffix: kW
+ expr: 1000 * watt
+
+# Useful derived units
+- id: whpermile
+ aliases:
+ - watthourspermile
+ suffix: Wh/mi
+ expr: (watt * hour) / mile
+
+- id: milesperkwh
+ aliases:
+ - miperkwh
+ suffix: mi/kWh
+ expr: mile / (kilowatt * hour)
+
diff --git a/src/definitions.rs b/src/definitions.rs
index 32ee8be..5a414dd 100644
--- a/src/definitions.rs
+++ b/src/definitions.rs
@@ -1,8 +1,11 @@
use serde_yaml;
+use exprparser;
+use qexpr;
+use qvalue::*;
use types::{NamedValue, Value};
-use std::collections::HashSet;
+use std::collections::{HashMap, HashSet};
#[derive(Debug, Deserialize)]
pub struct RawECURequest {
@@ -249,3 +252,104 @@ impl Iterator for CadencedECUs {
}
}
}
+
+#[derive(Debug, Deserialize)]
+struct RawUnit {
+ id: String,
+ aliases: Vec<String>,
+ suffix: String,
+ expr: String,
+}
+
+impl RawUnit {
+ fn get_all() -> &'static [RawUnit] {
+ lazy_static! {
+ static ref UNITS: Vec<RawUnit> =
+ serde_yaml::from_slice(include_bytes!("../definitions/units.yaml")).unwrap();
+ }
+ &UNITS
+ }
+}
+
+#[derive(Debug)]
+pub struct Units {
+ raw: &'static [RawUnit],
+ qvals: Vec<QValue>,
+ all: HashMap<String, usize>,
+}
+
+impl Units {
+ pub fn get() -> &'static Units {
+ lazy_static! {
+ static ref UNITS: Units = Units::new();
+ }
+ &UNITS
+ }
+
+ fn new() -> Units {
+ let raw = RawUnit::get_all();
+ let mut qvals = Vec::new();
+ let mut allsyms = HashMap::new();
+ let mut symbols = HashMap::new();
+
+ symbols.insert(
+ "raw.voltage".to_owned(),
+ QValue::unit(BaseQuantity::Voltage),
+ );
+ symbols.insert(
+ "raw.current".to_owned(),
+ QValue::unit(BaseQuantity::Current),
+ );
+ symbols.insert(
+ "raw.temperature".to_owned(),
+ QValue::unit(BaseQuantity::Temperature),
+ );
+ symbols.insert(
+ "raw.distance".to_owned(),
+ QValue::unit(BaseQuantity::Distance),
+ );
+ symbols.insert("raw.time".to_owned(), QValue::unit(BaseQuantity::Time));
+
+ for i in 0..raw.len() {
+ if let Some(parsed) = exprparser::parse_expression(&raw[i].expr) {
+ if let Some(unit) = qexpr::evaluate(&parsed, &mut symbols) {
+ qvals.push(unit);
+ if allsyms.contains_key(&raw[i].id) {
+ panic!("Duplicated unit name/alias: {}", &raw[i].id);
+ }
+ allsyms.insert(raw[i].id.clone(), i);
+ symbols.insert(raw[i].id.clone(), unit);
+ for alias in &raw[i].aliases {
+ if allsyms.contains_key(alias) {
+ panic!("Duplicated unit name/alias: {}", alias);
+ }
+ allsyms.insert(alias.clone(), i);
+ symbols.insert(alias.clone(), unit);
+ }
+ } else {
+ println!("Current symbols: {:?}", symbols);
+ println!("Expression: {:?}", parsed);
+ panic!("Unable to evaluate units expression for {}", raw[i].id);
+ }
+ } else {
+ panic!("Unable to parse units expression for {}", raw[i].id);
+ }
+ }
+
+ Units {
+ raw: raw,
+ qvals: qvals,
+ all: allsyms,
+ }
+ }
+
+ pub fn count(&self) -> usize {
+ self.raw.len()
+ }
+
+ pub fn populate(&self, into: &mut HashMap<String, QValue>) {
+ self.all.iter().for_each(|(k, v)| {
+ into.insert(k.clone(), self.qvals[*v].clone());
+ });
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index 45c55ac..319894d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -59,17 +59,11 @@ fn packet_print(id: u16, bytes: &[u8]) -> String {
fn main() {
env_logger::init();
- {
- // Basic test for parser etc. just to quieten vscode for now.
-
- let expr = exprparser::parse_expression("14*9").expect("Should parse");
- let symb = HashMap::new();
- let _res = qexpr::evaluate(&expr, &symb);
- }
-
let raw_defs = definitions::RawECUEntry::get_all();
+ let units = definitions::Units::get();
info!("Read {} raw ecu entries", raw_defs.len());
+ info!("Read {} unit definitions", units.count());
let world = futures::future::lazy(move || {
let args: Vec<String> = args().collect();
diff --git a/src/qvalue.rs b/src/qvalue.rs
index 42b88c2..85d7d32 100644
--- a/src/qvalue.rs
+++ b/src/qvalue.rs
@@ -22,7 +22,7 @@ impl BaseQuantity {
}
// Note, this max value has to be sync'd with the BaseQuantity above
-#[derive(Eq, PartialEq, Clone, Copy)]
+#[derive(Eq, PartialEq, Clone, Copy, Debug)]
pub struct Quantifier([i8; 5]);
impl Quantifier {
@@ -83,7 +83,7 @@ impl ops::Div for Quantifier {
}
}
-#[derive(PartialEq, Clone, Copy)]
+#[derive(PartialEq, Clone, Copy, Debug)]
pub struct QValue {
val: f64,
q: Quantifier,