Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Graph support, no UI Graph, just the the logic #93

Merged
merged 5 commits into from
Apr 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .config/settings.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
theme = "Light"
update_delay = 1500
current_config = "fake"
current_config = "test"
20 changes: 19 additions & 1 deletion .config/test.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,22 @@
Control = []
Fan = []
Temp = []
Flat = []
Linear = []
Target = []

[[CustomTemp]]
name = "CPU"
kind = "Average"
inputs = []
inputs = []

[[Graph]]
name = "Graph"

[[Graph.coord]]
temp = 50
percent = 30

[[Graph.coord]]
temp = 50
percent = 30
2 changes: 1 addition & 1 deletion DEV.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
[[Graph]]
name = "Graph"
input = "max"
cood = [
coord = [
{ temp = 50, percent = 30 },
{ temp = 50, percent = 30 },
{ temp = 50, percent = 30 },
Expand Down
5 changes: 5 additions & 0 deletions data/src/app_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@ impl AppGraph {
app_graph.insert_node(node);
}

for graph in config.graphs {
let node = graph.to_node(&mut app_graph.id_generator, &app_graph.nodes, hardware);
app_graph.insert_node(node);
}

for control in config.controls {
let node = control.to_node(&mut app_graph.id_generator, &app_graph.nodes, hardware);
app_graph.insert_node(node);
Expand Down
228 changes: 222 additions & 6 deletions data/src/config/graph.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,239 @@
use serde::{Deserialize, Serialize};
use std::vec;

use crate::node::IsValid;
use hardware::{Hardware, Value};
use serde::{Deserialize, Deserializer, Serialize};

#[derive(Serialize, Deserialize, Debug, Clone)]
use crate::{
app_graph::Nodes,
config::graph::affine::Affine,
id::IdGenerator,
node::{IsValid, Node, NodeType, ToNode},
update::UpdateError,
};

#[derive(Serialize, Deserialize, Debug, Clone, Eq)]
pub struct Coord {
pub temp: u8,
pub percent: u8,
}

#[derive(Serialize, Deserialize, Debug, Clone, Default)]
impl TryFrom<(&str, &str)> for Coord {
type Error = Box<dyn std::error::Error>;

fn try_from((temp, percent): (&str, &str)) -> Result<Self, Self::Error> {
let temp = temp.parse::<u8>()?;

let percent = percent.parse::<u8>()?;

if percent > 100 {
return Err("Percent > 100".into());
}

Ok(Coord { temp, percent })
}
}

impl PartialEq for Coord {
fn eq(&self, other: &Self) -> bool {
self.temp == other.temp
}
}

impl PartialOrd for Coord {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}

impl Ord for Coord {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.temp.cmp(&other.temp)
}
}

impl Coord {
pub fn exact_same(&self, other: &Self) -> bool {
self.percent == other.percent && self.temp == other.temp
}
}

// todo: better default + UI
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Graph {
pub name: String,
#[serde(rename = "coord")]
pub coords: Vec<Coord>,
pub coords: Coords,
pub input: Option<String>, // Temp or CustomTemp
}

impl Default for Graph {
fn default() -> Self {
Self {
name: Default::default(),
coords: Coords(vec![
Coord {
temp: 10,
percent: 10,
},
Coord {
temp: 70,
percent: 100,
},
]),
input: Default::default(),
}
}
}

impl ToNode for Graph {
fn to_node(self, id_generator: &mut IdGenerator, nodes: &Nodes, _hardware: &Hardware) -> Node {
Node::new(id_generator, NodeType::Graph(self), nodes)
}
}

impl IsValid for Graph {
fn is_valid(&self) -> bool {
self.input.is_some() //TODO: add conditions on coords
#[derive(PartialEq)]
enum DupState {
Init,
Prev { temp: u8 },
DuplicateFound,
}

self.input.is_some()
&& !self.coords.0.is_empty()
&& self
.coords
.0
.iter()
.fold(DupState::Init, |prev, coord| match prev {
DupState::Init => DupState::Prev { temp: coord.temp },
DupState::Prev { temp } => {
if temp == coord.temp {
DupState::DuplicateFound
} else {
DupState::Prev { temp: coord.temp }
}
}
DupState::DuplicateFound => DupState::DuplicateFound,
})
!= DupState::DuplicateFound
&& !self.coords.0.iter().any(|coord| coord.percent > 100)
}
}

#[derive(Serialize, Debug, Clone, Default)]
pub struct Coords(pub Vec<Coord>);

impl<'de> serde::Deserialize<'de> for Coords {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
let mut s: Vec<Coord> = Vec::deserialize(d)?;

s.sort();

Ok(Coords(s))
}
}

impl Graph {
pub fn get_value(&self, value: Value) -> Result<Value, UpdateError> {
let dummy_coord = Coord {
temp: value as u8,
percent: 0,
};

let res = match self.coords.0.binary_search(&dummy_coord) {
Ok(index) => self.coords.0[index].percent as Value,
Err(index) => {
if index == 0 {
self.coords.0[index].percent as Value
} else if index == self.coords.0.len() {
self.coords.0[index - 1].percent as Value
} else {
let coord1 = &self.coords.0[index - 1];
let coord2 = &self.coords.0[index];

Affine {
xa: coord1.temp.into(),
ya: coord1.percent.into(),
xb: coord2.temp.into(),
yb: coord2.percent.into(),
}
.calcule(value) as Value
}
}
};

Ok(res)
}
}

// todo: use it in linear
mod affine {
use hardware::Value;

#[derive(Debug)]
pub struct Affine {
pub xa: f32,
pub ya: f32,
pub xb: f32,
pub yb: f32,
}

impl Affine {
pub fn calcule(&self, value: Value) -> f32 {
let a = (self.yb - self.ya) / (self.xb - self.xa);
let b = self.ya - a * self.xa;

a * value as f32 + b
}
}
}

#[test]
fn test() {
let coord1 = Coord {
temp: 10,
percent: 10,
};

let coord2 = Coord {
temp: 20,
percent: 20,
};

let coord3 = Coord {
temp: 30,
percent: 30,
};

let coord4 = Coord {
temp: 40,
percent: 40,
};

let coords = Coords(vec![coord1, coord2, coord3, coord4]);

let dummy_coord = Coord {
temp: 50,
percent: 0,
};

let res = coords.0.binary_search(&dummy_coord);

match res {
Ok(index) => {
println!("use {}", index);
}
Err(index) => {
if index == 0 {
println!("use {}", index);
} else if index == coords.0.len() {
println!("use {}", index - 1);
} else {
println!("use {} and {}", index - 1, index);
}
}
}
dbg!(&res);
}
6 changes: 3 additions & 3 deletions data/src/config/serde_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use super::custom_temp::{CustomTemp, CustomTempKind};

use super::fan::Fan;
use super::flat::Flat;
use super::graph::{Coord, Graph};
use super::graph::{Coord, Coords, Graph};
use super::linear::Linear;
use super::target::Target;
use super::temp::Temp;
Expand Down Expand Up @@ -154,7 +154,7 @@ fn config1() -> Config {
)],
graphs: vec![Graph {
name: "Graph".into(),
coords: vec![
coords: Coords(vec![
Coord {
temp: 10,
percent: 10,
Expand All @@ -163,7 +163,7 @@ fn config1() -> Config {
temp: 50,
percent: 30,
},
],
]),
input: Some("max".into()),
}],
flats: vec![Flat {
Expand Down
11 changes: 2 additions & 9 deletions data/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,16 +371,9 @@ impl NodeType {
NodeType::Temp(_) => Ordering::Greater,
_ => Ordering::Less,
},
NodeType::Graph(_) => todo!(),
NodeType::Flat(_) => Ordering::Equal,
NodeType::Linear(..) => match other {
NodeType::Control(_) => Ordering::Less,
NodeType::Fan(_) => Ordering::Greater,
NodeType::Temp(_) => Ordering::Greater,
NodeType::CustomTemp(_) => Ordering::Greater,
_ => Ordering::Equal,
},
NodeType::Target(..) => match other {

NodeType::Graph(_) | NodeType::Linear(..) | NodeType::Target(..) => match other {
NodeType::Control(_) => Ordering::Less,
NodeType::Fan(_) => Ordering::Greater,
NodeType::Temp(_) => Ordering::Greater,
Expand Down
2 changes: 1 addition & 1 deletion data/src/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ impl Node {
crate::node::NodeType::Fan(fan) => fan.get_value(bridge),
crate::node::NodeType::Temp(temp) => temp.get_value(bridge),
crate::node::NodeType::CustomTemp(custom_temp) => custom_temp.get_value(input_values),
crate::node::NodeType::Graph(_) => todo!(),
crate::node::NodeType::Graph(graph) => graph.get_value(input_values[0]),
crate::node::NodeType::Flat(flat) => Ok(flat.value.into()),
crate::node::NodeType::Linear(linear, ..) => linear.get_value(input_values[0]),
crate::node::NodeType::Target(target, ..) => target.get_value(input_values[0]),
Expand Down
26 changes: 26 additions & 0 deletions data/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::cmp::Ordering;

pub trait RemoveElem<T> {
fn remove_elem<F>(&mut self, predicate: F) -> Option<T>
where
Expand All @@ -22,3 +24,27 @@ pub fn init_test_logging() {
.is_test(true)
.try_init();
}

pub trait InsertSorted<T> {
fn insert_sorted<F>(&mut self, predicate: F, element: T) -> Option<T>
where
F: Fn(&T) -> Ordering;
}

impl<T> InsertSorted<T> for Vec<T> {
fn insert_sorted<F>(&mut self, predicate: F, element: T) -> Option<T>
where
F: Fn(&T) -> Ordering,
{
match self.binary_search_by(predicate) {
Ok(index) => {
let removed = std::mem::replace(&mut self[index], element);
Some(removed)
}
Err(index) => {
self.insert(index, element);
None
}
}
}
}
Loading