diff --git a/.config/config3.toml b/.config/config3.toml new file mode 100644 index 00000000..8f384790 --- /dev/null +++ b/.config/config3.toml @@ -0,0 +1,32 @@ +[[Control]] +name = "control1" +input = "linear1" +auto = false + +[[Linear]] +name = "linear1" +minTemp = 10 +minSpeed = 10 +maxTemp = 70 +maxSpeed = 100 +input = "custom_temp" + +[[CustomTemp]] +name = "custom_temp" +kind = "Average" +input = [ + "temp1", + "temp2", +] + + + + + +[[Temp]] +name = "temp1" +id = "/intelcpu/0/temperature/1" + +[[Temp]] +name = "temp2" +id = "/intelcpu/0/temperature/2" \ No newline at end of file diff --git a/.config/config4.toml b/.config/config4.toml new file mode 100644 index 00000000..0df1c196 --- /dev/null +++ b/.config/config4.toml @@ -0,0 +1,28 @@ +[[Control]] +name = "control1" +input = "linear1" +auto = false + +[[Linear]] +name = "linear1" +minTemp = 10 +minSpeed = 10 +maxTemp = 70 +maxSpeed = 100 +input = "custom_temp" + +[[CustomTemp]] +name = "custom_temp" +kind = "Average" +input = [ + "temp1", + "temp2", +] + +[[Temp]] +name = "temp1" +id = "coretemp-isa-0000-temp3_input" + +[[Temp]] +name = "temp2" +id = "coretemp-isa-0000-temp2_input" \ No newline at end of file diff --git a/.config/hardware.toml b/.config/hardware.toml deleted file mode 100644 index c82f900b..00000000 --- a/.config/hardware.toml +++ /dev/null @@ -1,17 +0,0 @@ -Fan = [] - -[[Control]] -name = "control1" -id = "control1" - -[[Control]] -name = "control2" -id = "control2" - -[[Temp]] -name = "temp1" -id = "temp1" - -[[Temp]] -name = "temp2" -id = "temp2" diff --git a/.config/settings.toml b/.config/settings.toml index e1bd9cc3..b014f806 100644 --- a/.config/settings.toml +++ b/.config/settings.toml @@ -1,4 +1,4 @@ unit = "Celsius" update_delay = 0 disable_pwm_value = 0 -current_config = "config2.toml" +current_config = "config4.toml" diff --git a/.gitignore b/.gitignore index 5f7a041f..aa7ead3f 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,5 @@ target/ .vscode/* !.vscode/launch.json bin/ -obj/ \ No newline at end of file +obj/ +.config/hardware.toml diff --git a/Cargo.lock b/Cargo.lock index d51b6dd2..26ade36e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1287,6 +1287,7 @@ version = "0.1.0" dependencies = [ "lm-sensors", "log", + "ouroboros", "rand", "serde", "serde_json", @@ -1575,6 +1576,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.9" @@ -2121,6 +2131,31 @@ dependencies = [ "libredox 0.0.2", ] +[[package]] +name = "ouroboros" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c86de06555b970aec45229b27291b53154f21a5743a163419f4e4c0b065dcde" +dependencies = [ + "aliasable", + "ouroboros_macro", + "static_assertions", +] + +[[package]] +name = "ouroboros_macro" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cad0c4b129e9696e37cb712b243777b90ef489a0bfaa0ac34e7d9b860e4f134" +dependencies = [ + "heck", + "itertools", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "owned_ttf_parser" version = "0.20.0" @@ -2368,6 +2403,30 @@ dependencies = [ "toml_edit 0.20.7", ] +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.69" diff --git a/Makefile b/Makefile index c9b4718c..b4f04bfe 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ fix: cargo clippy --all --fix --allow-dirty --allow-staged cargo fmt --all -clean-git: +git-cache: git rm -rf --cached . git add . @@ -35,6 +35,9 @@ clean-libsensors: lhm: dotnet build ./hardware/LibreHardwareMonitorWrapper/ -c release +run-lhm: + dotnet run --project ./hardware/LibreHardwareMonitorWrapper/ -c release + test: cargo test --all --all-features diff --git a/data/src/config/control.rs b/data/src/config/control.rs index ac5b3f68..b12d414b 100644 --- a/data/src/config/control.rs +++ b/data/src/config/control.rs @@ -1,6 +1,6 @@ use std::rc::Rc; -use hardware::{ControlH, Hardware, Value}; +use hardware::{ControlH, Hardware, HardwareBridgeT, Value}; use serde::{Deserialize, Serialize}; use crate::{ @@ -42,26 +42,32 @@ impl Control { } } - pub fn set_value(&mut self, value: Value) -> Result { + pub fn set_value( + &mut self, + value: Value, + bridge: &mut HardwareBridgeT, + ) -> Result { if !self.manual_has_been_set { - self.set_mode(false)?; + self.set_mode(false, bridge)?; } match &self.control_h { - Some(control_h) => control_h - .bridge - .set_value(value) + Some(control_h) => bridge + .set_value(&control_h.internal_index, value) .map(|_| value) .map_err(UpdateError::Hardware), None => Err(UpdateError::NodeIsInvalid), } } - pub fn set_mode(&mut self, auto: bool) -> Result<(), UpdateError> { + pub fn set_mode( + &mut self, + auto: bool, + bridge: &mut HardwareBridgeT, + ) -> Result<(), UpdateError> { let res = match &self.control_h { - Some(control_h) => control_h - .bridge - .set_mode(!auto as i32) + Some(control_h) => bridge + .set_mode(&control_h.internal_index, !auto as i32) .map_err(UpdateError::Hardware), None => Err(UpdateError::NodeIsInvalid), }; diff --git a/data/src/config/fan.rs b/data/src/config/fan.rs index b1f89973..b9fd902d 100644 --- a/data/src/config/fan.rs +++ b/data/src/config/fan.rs @@ -1,6 +1,6 @@ use std::rc::Rc; -use hardware::{FanH, Hardware, Value}; +use hardware::{FanH, Hardware, HardwareBridgeT, Value}; use serde::{Deserialize, Serialize}; use crate::{ @@ -20,9 +20,11 @@ pub struct Fan { } impl Fan { - pub fn get_value(&self) -> Result { + pub fn get_value(&self, bridge: &mut HardwareBridgeT) -> Result { match &self.fan_h { - Some(fan_h) => fan_h.bridge.get_value().map_err(UpdateError::Hardware), + Some(fan_h) => bridge + .get_value(&fan_h.internal_index) + .map_err(UpdateError::Hardware), None => Err(UpdateError::NodeIsInvalid), } } diff --git a/data/src/config/serde_test.rs b/data/src/config/serde_test.rs index 800a232d..49eaa665 100644 --- a/data/src/config/serde_test.rs +++ b/data/src/config/serde_test.rs @@ -1,5 +1,5 @@ use const_format::formatcp; -use hardware::{ControlH, FanH, Hardware, HardwareItem, TempH}; +use hardware::{ControlH, FanH, Hardware, TempH}; use serial_test::serial; use std::fmt::Debug; use std::fs::{self, File}; @@ -95,44 +95,27 @@ fn write_file(path: &str, content_generation: impl Fn() -> Result Result { - todo!() - } - - fn set_value(&self, _value: hardware::Value) -> Result<(), hardware::HardwareError> { - todo!() - } - - fn set_mode(&self, _value: hardware::Value) -> Result<(), hardware::HardwareError> { - todo!() - } -} - fn hardware1() -> Hardware { Hardware { controls: vec![ControlH { name: "ControlH".into(), hardware_id: "ControlH".into(), info: "ControlH".into(), - bridge: Box::new(T {}), + internal_index: 0, } .into()], temps: vec![TempH { name: "TempH".into(), hardware_id: "TempH".into(), info: "TempH".into(), - bridge: Box::new(T {}), + internal_index: 0, } .into()], fans: vec![FanH { name: "FanH".into(), hardware_id: "FanH".into(), info: "FanH".into(), - bridge: Box::new(T {}), + internal_index: 0, } .into()], } diff --git a/data/src/config/temp.rs b/data/src/config/temp.rs index 81d6af47..8e990d91 100644 --- a/data/src/config/temp.rs +++ b/data/src/config/temp.rs @@ -1,6 +1,6 @@ use std::rc::Rc; -use hardware::{Hardware, TempH, Value}; +use hardware::{Hardware, HardwareBridgeT, TempH, Value}; use serde::{Deserialize, Serialize}; use crate::{ @@ -20,9 +20,11 @@ pub struct Temp { } impl Temp { - pub fn get_value(&self) -> Result { + pub fn get_value(&self, bridge: &mut HardwareBridgeT) -> Result { match &self.temp_h { - Some(temp_h) => temp_h.bridge.get_value().map_err(UpdateError::Hardware), + Some(temp_h) => bridge + .get_value(&temp_h.internal_index) + .map_err(UpdateError::Hardware), None => Err(UpdateError::NodeIsInvalid), } } diff --git a/data/src/lib.rs b/data/src/lib.rs index 75147167..cca0c057 100644 --- a/data/src/lib.rs +++ b/data/src/lib.rs @@ -13,7 +13,7 @@ pub mod node; pub mod settings; pub mod update; -use hardware::{Hardware, HardwareBridge}; +use hardware::{Hardware, HardwareBridge, HardwareBridgeT}; use node::AppGraph; use update::Update; @@ -25,6 +25,7 @@ pub struct AppState { pub dir_manager: DirManager, pub settings: Settings, pub hardware: Hardware, + pub bridge: HardwareBridgeT, pub app_graph: AppGraph, pub update: Update, } diff --git a/data/src/update.rs b/data/src/update.rs index be32fe72..f520382e 100644 --- a/data/src/update.rs +++ b/data/src/update.rs @@ -1,6 +1,6 @@ use std::collections::HashSet; -use hardware::{HardwareError, Value}; +use hardware::{HardwareBridgeT, HardwareError, Value}; use crate::{ id::Id, @@ -30,11 +30,16 @@ impl Update { Self {} } - pub fn graph(&mut self, nodes: &mut Nodes, root_nodes: &RootNodes) -> Result<(), UpdateError> { + pub fn graph( + &mut self, + nodes: &mut Nodes, + root_nodes: &RootNodes, + bridge: &mut HardwareBridgeT, + ) -> Result<(), UpdateError> { let mut updated: HashSet = HashSet::new(); for node_id in root_nodes { - Self::update_rec(nodes, node_id, &mut updated)?; + Self::update_rec(nodes, node_id, &mut updated, bridge)?; } Ok(()) } @@ -45,6 +50,7 @@ impl Update { nodes: &mut Nodes, node_id: &Id, updated: &mut HashSet, + bridge: &mut HardwareBridgeT, ) -> Result, UpdateError> { if updated.contains(node_id) { return match nodes.get(node_id) { @@ -67,7 +73,7 @@ impl Update { } for id in &input_ids { - match Self::update_rec(nodes, id, updated)? { + match Self::update_rec(nodes, id, updated, bridge)? { Some(value) => input_values.push(value), None => return Ok(None), } @@ -77,7 +83,7 @@ impl Update { return Err(UpdateError::NodeNotFound); }; - node.update(&input_values)?; + node.update(&input_values, bridge)?; updated.insert(node.id); Ok(node.value) @@ -85,12 +91,17 @@ impl Update { } impl Node { - pub fn update(&mut self, input_values: &Vec) -> Result<(), UpdateError> { + pub fn update( + &mut self, + input_values: &Vec, + bridge: &mut HardwareBridgeT, + ) -> Result<(), UpdateError> { let value = match &mut self.node_type { - crate::node::NodeType::Control(control) => control.set_value(input_values[0])?, - - crate::node::NodeType::Fan(fan) => fan.get_value()?, - crate::node::NodeType::Temp(temp) => temp.get_value()?, + crate::node::NodeType::Control(control) => { + control.set_value(input_values[0], bridge)? + } + 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.update(input_values)?, crate::node::NodeType::Graph(_) => todo!(), crate::node::NodeType::Flat(flat) => flat.value.into(), diff --git a/hardware/Cargo.toml b/hardware/Cargo.toml index 501d38a8..4b85d48c 100644 --- a/hardware/Cargo.toml +++ b/hardware/Cargo.toml @@ -8,14 +8,16 @@ fake_hardware = ["rand"] [dependencies] -serde.workspace = true -serde_json.workspace = true log.workspace = true - - +serde.workspace = true +ouroboros = "0.18" rand = {version = "0.8", optional = true} [target.'cfg(target_os = "linux")'.dependencies] lm-sensors = { git = "https://github.com/wiiznokes/lm-sensors.git", branch = "pwm" } + +[target.'cfg(target_os = "windows")'.dependencies] +serde_json.workspace = true + [dev-dependencies] \ No newline at end of file diff --git a/hardware/LibreHardwareMonitorWrapper/Hardware/BaseHardware.cs b/hardware/LibreHardwareMonitorWrapper/Hardware/BaseHardware.cs deleted file mode 100644 index 39af82b3..00000000 --- a/hardware/LibreHardwareMonitorWrapper/Hardware/BaseHardware.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace LibreHardwareMonitorWrapper.Hardware; - -public abstract class BaseHardware -{ - protected BaseHardware(string id, string name, int index, HardwareType type) - { - Id = id; - Name = name; - Index = index; - Type = type; - } - - public string Id { get; } - public string Name { get; } - public int Index { get; } - - - public HardwareType Type { get; } -} \ No newline at end of file diff --git a/hardware/LibreHardwareMonitorWrapper/HardwareManager.cs b/hardware/LibreHardwareMonitorWrapper/HardwareManager.cs index 1b8d7118..cd713e14 100644 --- a/hardware/LibreHardwareMonitorWrapper/HardwareManager.cs +++ b/hardware/LibreHardwareMonitorWrapper/HardwareManager.cs @@ -1,48 +1,52 @@ using LibreHardwareMonitorWrapper.Hardware; +using LibreHardwareMonitorWrapper.Lhm; namespace LibreHardwareMonitorWrapper; public static class HardwareManager { - private static readonly Lhm Lhm = new(); + private static readonly HardwareResearcher HardwareResearcher = new(); public static void Start() { - Lhm.Start(); - Lhm.CreateHardware(); + HardwareResearcher.Start(); + HardwareResearcher.CreateHardware(); } - public static int GetValue(HardwareType type, int index) + public static int GetValue(int index) { - Lhm.Update(); - return type switch + HardwareResearcher.Update(); + var hardware = State.Hardwares[index]; + return hardware.Type switch { - HardwareType.Control => State.Controls[index].Value(), - HardwareType.Fan => State.Fans[index].Value(), - HardwareType.Temp => State.Temps[index].Value(), - _ => throw new ArgumentOutOfRangeException(nameof(type), type, null) + HardwareType.Control => (hardware as Control)!.Value(), + HardwareType.Fan => (hardware as Sensor)!.Value(), + HardwareType.Temp => (hardware as Sensor)!.Value(), + _ => throw new ArgumentOutOfRangeException() }; } public static void SetValue(int index, int value) { - State.Controls[index].SetSpeed(value); + var control = State.Hardwares[index] as Control; + control!.SetSpeed(value); } public static void SetAuto(int index) { - State.Controls[index].SetAuto(); + var control = State.Hardwares[index] as Control; + control!.SetAuto(); } public static void Stop() { - Lhm.Stop(); + HardwareResearcher.Stop(); } public static void Update() { - Lhm.Update(); + HardwareResearcher.Update(); } } \ No newline at end of file diff --git a/hardware/LibreHardwareMonitorWrapper/Hardware/Control.cs b/hardware/LibreHardwareMonitorWrapper/Lhm/Control.cs similarity index 90% rename from hardware/LibreHardwareMonitorWrapper/Hardware/Control.cs rename to hardware/LibreHardwareMonitorWrapper/Lhm/Control.cs index 5ee1f4d6..680f6941 100644 --- a/hardware/LibreHardwareMonitorWrapper/Hardware/Control.cs +++ b/hardware/LibreHardwareMonitorWrapper/Lhm/Control.cs @@ -7,7 +7,8 @@ public class Control : BaseHardware private readonly ISensor _mSensor; private bool _isSetSpeed; - public Control(string id, string name, ISensor sensor, int index) : base(id, name, index, HardwareType.Control) + public Control(string id, string name, string info, ISensor sensor, int index) : base(id, name, info, index, + HardwareType.Control) { _mSensor = sensor; } diff --git a/hardware/LibreHardwareMonitorWrapper/Hardware/LHM.cs b/hardware/LibreHardwareMonitorWrapper/Lhm/HardwareResearcher.cs similarity index 78% rename from hardware/LibreHardwareMonitorWrapper/Hardware/LHM.cs rename to hardware/LibreHardwareMonitorWrapper/Lhm/HardwareResearcher.cs index 65114d49..bc53646c 100644 --- a/hardware/LibreHardwareMonitorWrapper/Hardware/LHM.cs +++ b/hardware/LibreHardwareMonitorWrapper/Lhm/HardwareResearcher.cs @@ -1,8 +1,9 @@ using LibreHardwareMonitor.Hardware; +using LibreHardwareMonitorWrapper.Hardware; -namespace LibreHardwareMonitorWrapper.Hardware; +namespace LibreHardwareMonitorWrapper.Lhm; -public class Lhm : IVisitor +public class HardwareResearcher : IVisitor { private readonly Computer _mComputer = new() { @@ -66,6 +67,7 @@ public void CreateHardware() var nbControl = 0; var nbFan = 0; var nbTemp = 0; + var nbTot = 0; var hardwareArray = _mComputer.Hardware; @@ -82,6 +84,9 @@ public void CreateHardware() } } + Console.WriteLine("nbControl: " + nbControl); + Console.WriteLine("nbFan: " + nbFan); + Console.WriteLine("nbTemp: " + nbTemp); return; void AddHardware(ISensor sensor) @@ -96,22 +101,24 @@ void AddHardware(ISensor sensor) { case SensorType.Control: id ??= SensorType.Control.ToString() + nbControl; - State.Controls.Add(new Control(id, name, sensor, nbControl)); + State.Hardwares.Add(new Control(id, name, name, sensor, nbTot)); nbControl += 1; break; case SensorType.Fan: - id ??= SensorType.Control.ToString() + nbFan; - State.Fans.Add(new Sensor(id, name, sensor, nbFan, HardwareType.Fan)); + id ??= SensorType.Fan.ToString() + nbFan; + State.Hardwares.Add(new Sensor(id, name, name, sensor, nbTot, HardwareType.Fan)); nbFan += 1; break; case SensorType.Temperature: - id ??= SensorType.Control.ToString() + nbTemp; - State.Temps.Add(new Sensor(id, name, sensor, nbTemp, HardwareType.Temp)); + id ??= SensorType.Temperature.ToString() + nbTemp; + State.Hardwares.Add(new Sensor(id, name, name, sensor, nbTot, HardwareType.Temp)); nbTemp += 1; break; default: throw new Exception("wrong sensor type"); } + + nbTot += 1; } } diff --git a/hardware/LibreHardwareMonitorWrapper/Hardware/Sensor.cs b/hardware/LibreHardwareMonitorWrapper/Lhm/Sensor.cs similarity index 57% rename from hardware/LibreHardwareMonitorWrapper/Hardware/Sensor.cs rename to hardware/LibreHardwareMonitorWrapper/Lhm/Sensor.cs index 583e92fe..46053412 100644 --- a/hardware/LibreHardwareMonitorWrapper/Hardware/Sensor.cs +++ b/hardware/LibreHardwareMonitorWrapper/Lhm/Sensor.cs @@ -1,12 +1,13 @@ using LibreHardwareMonitor.Hardware; -namespace LibreHardwareMonitorWrapper.Hardware; +namespace LibreHardwareMonitorWrapper.Lhm; public class Sensor : BaseHardware { private readonly ISensor _mSensor; - public Sensor(string id, string name, ISensor sensor, int index, HardwareType type) : base(id, name, index, type) + public Sensor(string id, string name, string info, ISensor sensor, int index, HardwareType type) : base(id, name, + info, index, type) { _mSensor = sensor; } diff --git a/hardware/LibreHardwareMonitorWrapper/Program.cs b/hardware/LibreHardwareMonitorWrapper/Program.cs index c42a7050..91e13651 100644 --- a/hardware/LibreHardwareMonitorWrapper/Program.cs +++ b/hardware/LibreHardwareMonitorWrapper/Program.cs @@ -4,7 +4,6 @@ HardwareManager.Start(); -var hardwareList = State.GetHardwareData(); var serializerOptions = new JsonSerializerOptions { @@ -15,12 +14,13 @@ }; -var jsonText = JsonSerializer.Serialize(hardwareList, serializerOptions); - +var jsonText = JsonSerializer.Serialize(State.Hardwares, serializerOptions); var server = new Server(); server.SendHardware(jsonText); +server.WaitForCommand(); -server.Shutdown(); \ No newline at end of file +server.Shutdown(); +HardwareManager.Stop(); \ No newline at end of file diff --git a/hardware/LibreHardwareMonitorWrapper/Server.cs b/hardware/LibreHardwareMonitorWrapper/Server.cs index ef9553de..d9a5f3fb 100644 --- a/hardware/LibreHardwareMonitorWrapper/Server.cs +++ b/hardware/LibreHardwareMonitorWrapper/Server.cs @@ -7,6 +7,7 @@ namespace LibreHardwareMonitorWrapper; public class Server { private const string Address = "127.0.0.1"; + private readonly byte[] _buffer = new byte[4]; private readonly Socket _client; private readonly Socket _listener; private int _port = 55555; @@ -23,33 +24,94 @@ public Server() public void SendHardware(string jsonText) { + var stringBuilder = new StringBuilder(jsonText); + stringBuilder.Append('\n'); + + var jsonTextWithLineDelimiter = stringBuilder.ToString(); + var stream = new NetworkStream(_client); - var bytes = Encoding.UTF8.GetBytes(jsonText); + var bytes = Encoding.UTF8.GetBytes(jsonTextWithLineDelimiter); + Console.WriteLine("Sending hardware"); stream.Write(bytes); + stream.Close(); + Console.WriteLine("Hardware send"); } public void WaitForCommand() { - var buffer = new byte[1024]; - var bytesRead = _client.Receive(buffer); + while (true) + { + Console.WriteLine("waiting for commands"); + var res = block_read(); + if (res < 0) return; - var message = Encoding.ASCII.GetString(buffer, 0, bytesRead); - Console.WriteLine("Received: " + message); + var command = (Command)res; + Console.WriteLine("Receive command: " + command); - // var responseBuffer = Encoding.ASCII.GetBytes("Hello from C#"); - var responseBuffer = "Hello from C#"u8.ToArray(); - _client.Send(responseBuffer); + int value; + int index; + switch (command) + { + case Command.SetAuto: + index = block_read(); + if (index < 0) return; + HardwareManager.SetAuto(index); + break; + case Command.SetValue: + index = block_read(); + if (index < 0) return; + value = block_read(); + if (value < 0) return; + HardwareManager.SetValue(index, value); + break; + case Command.GetValue: + index = block_read(); + if (index < 0) return; + Console.WriteLine("Receive index: " + index); + value = HardwareManager.GetValue(index); + var bytes = BitConverter.GetBytes(value); + Console.WriteLine("sending value: " + value); + if (!block_send(bytes)) return; + Console.WriteLine("value send"); + break; + case Command.Shutdown: + return; + default: + throw new ArgumentOutOfRangeException(); + } + } } - public void JustWait() + private bool block_send(byte[] bytes) { - var buffer = new byte[1024]; - var bytesRead = _client.Receive(buffer); - - var message = Encoding.ASCII.GetString(buffer, 0, bytesRead); - Console.WriteLine("Received: " + message); + try + { + var bytesSend = _client.Send(bytes); + return bytesSend != 0; + } + catch (Exception e) + { + Console.WriteLine(e); + return false; + } } + // return -1 if error + private int block_read() + { + try + { + var bytesRead = _client.Receive(_buffer); + if (bytesRead == 4) return BitConverter.ToInt32(_buffer, 0); + Console.WriteLine("byte read = " + bytesRead); + return -1; + } + catch (Exception e) + { + Console.WriteLine(e); + return -1; + } + } private void BindPort() { diff --git a/hardware/LibreHardwareMonitorWrapper/State.cs b/hardware/LibreHardwareMonitorWrapper/State.cs index 8af1a1a8..f1296ff2 100644 --- a/hardware/LibreHardwareMonitorWrapper/State.cs +++ b/hardware/LibreHardwareMonitorWrapper/State.cs @@ -1,28 +1,39 @@ -using LibreHardwareMonitorWrapper.Hardware; +namespace LibreHardwareMonitorWrapper; -namespace LibreHardwareMonitorWrapper; +public static class State +{ + public static readonly List Hardwares = new(); +} public enum HardwareType { - Control, - Fan, - Temp + Control = 1, + Fan = 2, + Temp = 3 } -public static class State +public enum Command { - public static readonly List Controls = new(); - public static readonly List Fans = new(); - public static readonly List Temps = new(); + SetAuto = 1, + SetValue = 2, + GetValue = 3, + Shutdown = 4 +} - public static List GetHardwareData() +public abstract class BaseHardware +{ + protected BaseHardware(string id, string name, string info, int index, HardwareType type) { - var list = new List(); - - list.AddRange(Controls); - list.AddRange(Fans); - list.AddRange(Temps); - - return list; + Id = id; + Name = name; + Index = index; + Type = type; + Info = info; } + + public string Id { get; } + public string Name { get; } + public string Info { get; } + public int Index { get; } + public HardwareType Type { get; } } \ No newline at end of file diff --git a/hardware/src/hardware_test.rs b/hardware/src/fake_hardware.rs similarity index 96% rename from hardware/src/hardware_test.rs rename to hardware/src/fake_hardware.rs index 7ad975fc..8daaa4ea 100644 --- a/hardware/src/hardware_test.rs +++ b/hardware/src/fake_hardware.rs @@ -4,7 +4,7 @@ use rand::Rng; use crate::{ControlH, Hardware, HardwareBridge, HardwareError, HardwareItem, TempH, Value}; -pub struct TestBridge {} +pub struct FakeHardwareBridge {} #[derive(Debug)] struct InternalSensor {} @@ -12,7 +12,7 @@ struct InternalSensor {} #[derive(Debug)] struct InternalControl {} -impl HardwareBridge for TestBridge { +impl HardwareBridge for FakeHardwareBridge { fn generate_hardware() -> Hardware { let mut hardware = Hardware::default(); diff --git a/hardware/src/lib.rs b/hardware/src/lib.rs index 45a1db2a..c15f2584 100644 --- a/hardware/src/lib.rs +++ b/hardware/src/lib.rs @@ -14,7 +14,7 @@ pub mod linux; pub mod windows; #[cfg(feature = "fake_hardware")] -pub mod hardware_test; +pub mod fake_hardware; #[derive(Debug, Clone)] pub enum HardwareError { @@ -23,9 +23,15 @@ pub enum HardwareError { } pub type Value = i32; - +pub type HardwareBridgeT = Box; pub trait HardwareBridge { - fn generate_hardware() -> Hardware; + fn generate_hardware() -> (Hardware, HardwareBridgeT) + where + Self: Sized; + + fn get_value(&mut self, internal_index: &usize) -> Result; + fn set_value(&mut self, internal_index: &usize, value: Value) -> Result<(), HardwareError>; + fn set_mode(&mut self, internal_index: &usize, value: Value) -> Result<(), HardwareError>; } #[derive(Debug, Clone, PartialEq, Eq)] @@ -35,20 +41,6 @@ pub enum HardwareType { Temp, } -pub trait HardwareItem: Debug { - fn get_value(&self) -> Result; - - fn set_value(&self, value: Value) -> Result<(), HardwareError>; - - fn set_mode(&self, value: Value) -> Result<(), HardwareError>; -} - -#[derive(Debug, Clone)] -pub struct InternalControlIndex { - pub io: usize, - pub enable: usize, -} - #[derive(Serialize, Debug)] pub struct ControlH { pub name: String, @@ -59,7 +51,7 @@ pub struct ControlH { pub info: String, #[serde(skip)] - pub bridge: Box, + pub internal_index: usize, } #[derive(Serialize, Debug)] @@ -72,7 +64,7 @@ pub struct FanH { pub info: String, #[serde(skip)] - pub bridge: Box, + pub internal_index: usize, } #[derive(Serialize, Debug)] @@ -84,7 +76,7 @@ pub struct TempH { pub info: String, #[serde(skip)] - pub bridge: Box, + pub internal_index: usize, } #[derive(Serialize, Debug, Clone, Default)] diff --git a/hardware/src/linux.rs b/hardware/src/linux.rs index 8e6a21c6..10ef735e 100644 --- a/hardware/src/linux.rs +++ b/hardware/src/linux.rs @@ -2,63 +2,58 @@ use std::fmt::Debug; use lm_sensors::{feature, value, ChipRef, FeatureRef, LMSensors, SubFeatureRef}; -use crate::{ControlH, FanH, Hardware, HardwareBridge, HardwareError, HardwareItem, TempH, Value}; - -pub struct LinuxBridge {} - -#[derive(Debug, Clone, PartialEq, Eq)] -enum SubFeatureType { - PwmIo, - PwmEnable, - Fan, - Temp, -} - -struct InternalSubFeatureRef { - sub_feature_type: SubFeatureType, - sub_feature_ref: SubFeatureRef<'static>, +use crate::{ + ControlH, FanH, Hardware, HardwareBridge, HardwareBridgeT, HardwareError, TempH, Value, +}; +use ouroboros::self_referencing; + +#[self_referencing] +pub struct LinuxBridge { + lib: LMSensors, + #[borrows(lib)] + #[not_covariant] + sensors: Vec>, } -impl Debug for InternalSubFeatureRef { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("InternalSubFeatureRef") - .field("sub_feature_type", &self.sub_feature_type) - .finish() - } -} -#[derive(Debug)] -struct InternalSensor { - sensor: InternalSubFeatureRef, -} +impl HardwareBridge for LinuxBridge { + fn generate_hardware() -> (Hardware, HardwareBridgeT) { + let mut hardware = Hardware::default(); -#[derive(Debug)] -struct InternalControl { - io: InternalSubFeatureRef, - enable: InternalSubFeatureRef, -} + let bridge = LinuxBridgeBuilder { + lib: lm_sensors::Initializer::default().initialize().unwrap(), + sensors_builder: |lib: &LMSensors| generate_hardware(lib, &mut hardware), + } + .build(); -impl Drop for InternalControl { - fn drop(&mut self) { - info!("pwm sould be set to auto"); - // TODO: set to auto + (hardware, Box::new(bridge)) } -} -impl HardwareBridge for LinuxBridge { - fn generate_hardware() -> Hardware { - let mut hardware = Hardware::default(); - - let lib = lm_sensors::Initializer::default().initialize().unwrap(); - let boxed = Box::new(lib); - // yes we leak like never here but it's not that bad in fact - // is even safe Rust. The kernel will be in charge to release - // memory when the process terminate. - let leaked: &'static mut LMSensors = Box::leak(boxed); - info!("lmsensors just leaked"); + fn get_value(&mut self, internal_index: &usize) -> Result { + self.with_sensors(|sensors| match sensors.get(*internal_index) { + Some(sensor) => match sensor { + InternalSubFeatureRef::Pwm(_) => { + panic!("can't get the value of a control"); + } + InternalSubFeatureRef::Sensor(sensor_refs) => match sensor_refs.io.raw_value() { + Ok(value) => Ok(value as i32), + Err(e) => { + error!("{}", e); + Err(HardwareError::LmSensors) + } + }, + }, + None => Err(HardwareError::IdNotFound), + }) + } - generate_hardware(leaked, &mut hardware); + fn set_value(&mut self, internal_index: &usize, value: Value) -> Result<(), HardwareError> { + debug!("set value {} to {}", value, internal_index); + Ok(()) + } - hardware + fn set_mode(&mut self, internal_index: &usize, value: Value) -> Result<(), HardwareError> { + debug!("set mode {} to {}", value, internal_index); + Ok(()) } } @@ -99,7 +94,40 @@ fn generate_id_name_info( Some((id, name, info)) } -fn generate_hardware(lib: &'static LMSensors, hardware: &mut Hardware) { +#[derive(Debug, Clone, PartialEq, Eq)] +enum SubFeatureType { + PwmIo, + PwmEnable, + Fan, + Temp, +} + +enum InternalSubFeatureRef<'a> { + Pwm(PwmRefs<'a>), + Sensor(SensorRefs<'a>), +} + +struct PwmRefs<'a> { + io: SubFeatureRef<'a>, + enable: SubFeatureRef<'a>, +} +struct SensorRefs<'a> { + io: SubFeatureRef<'a>, +} + +impl Drop for PwmRefs<'_> { + fn drop(&mut self) { + info!("pwm sould be set to auto"); + // TODO: set to auto + } +} + +fn generate_hardware<'a>( + lib: &'a LMSensors, + hardware: &mut Hardware, +) -> Vec> { + let mut sensors = Vec::new(); + for chip_ref in lib.chip_iter(None) { for feature_ref in chip_ref.feature_iter() { match feature_ref.kind() { @@ -114,16 +142,16 @@ fn generate_hardware(lib: &'static LMSensors, hardware: &mut Hardware) { if let Some((id, name, info)) = generate_id_name_info(&chip_ref, &feature_ref, &sub_feature_ref) { - let sensor = InternalSubFeatureRef { - sub_feature_type: SubFeatureType::Fan, - sub_feature_ref, - }; + let sensor = InternalSubFeatureRef::Sensor(SensorRefs { + io: sub_feature_ref, + }); + sensors.push(sensor); let fan_h = FanH { name, hardware_id: id, info, - bridge: Box::new(InternalSensor { sensor }), + internal_index: sensors.len() - 1, }; hardware.fans.push(fan_h.into()); } @@ -138,16 +166,16 @@ fn generate_hardware(lib: &'static LMSensors, hardware: &mut Hardware) { if let Some((id, name, info)) = generate_id_name_info(&chip_ref, &feature_ref, &sub_feature_ref) { - let sensor = InternalSubFeatureRef { - sub_feature_type: SubFeatureType::Temp, - sub_feature_ref, - }; + let sensor = InternalSubFeatureRef::Sensor(SensorRefs { + io: sub_feature_ref, + }); + sensors.push(sensor); let temp_h = TempH { name, hardware_id: id, info, - bridge: Box::new(InternalSensor { sensor }), + internal_index: sensors.len() - 1, }; hardware.temps.push(temp_h.into()); } @@ -167,23 +195,18 @@ fn generate_hardware(lib: &'static LMSensors, hardware: &mut Hardware) { if let Some((id, name, info)) = generate_id_name_info(&chip_ref, &feature_ref, &sub_feature_ref_io) { - let io = InternalSubFeatureRef { - sub_feature_type: SubFeatureType::PwmIo, - sub_feature_ref: sub_feature_ref_io, - }; - - let enable = InternalSubFeatureRef { - sub_feature_type: SubFeatureType::PwmEnable, - sub_feature_ref: sub_feature_ref_enable, - }; + let sensor = InternalSubFeatureRef::Pwm(PwmRefs { + io: sub_feature_ref_io, + enable: sub_feature_ref_enable, + }); - let control = InternalControl { io, enable }; + sensors.push(sensor); let control_h = ControlH { name, hardware_id: id, info, - bridge: Box::new(control), + internal_index: sensors.len() - 1, }; hardware.controls.push(control_h.into()); } @@ -194,40 +217,5 @@ fn generate_hardware(lib: &'static LMSensors, hardware: &mut Hardware) { }; } } -} - -impl HardwareItem for InternalSensor { - fn get_value(&self) -> Result { - match self.sensor.sub_feature_ref.raw_value() { - Ok(value) => Ok(value as i32), - Err(e) => { - error!("{}", e); - Err(HardwareError::LmSensors) - } - } - } - - fn set_value(&self, value: Value) -> Result<(), crate::HardwareError> { - panic!("can't set the value of a sensor"); - } - - fn set_mode(&self, value: Value) -> Result<(), HardwareError> { - panic!("can't set the mode of a sensor"); - } -} - -impl HardwareItem for InternalControl { - fn get_value(&self) -> Result { - panic!("can't get the value of a control"); - } - - fn set_value(&self, value: Value) -> Result<(), crate::HardwareError> { - debug!("set value {} to a control", value); - Ok(()) - } - - fn set_mode(&self, value: Value) -> Result<(), HardwareError> { - debug!("set mode {} to a control", value); - Ok(()) - } + sensors } diff --git a/hardware/src/windows.rs b/hardware/src/windows.rs index 9fe43953..4d5d4562 100644 --- a/hardware/src/windows.rs +++ b/hardware/src/windows.rs @@ -1,19 +1,154 @@ -use std::{io::Read, net::TcpStream}; +use std::{ + io::{BufRead, BufReader, Read, Write}, + net::TcpStream, + rc::Rc, +}; use serde::Deserialize; -use crate::{Hardware, HardwareBridge}; +use crate::{ + ControlH, FanH, Hardware, HardwareBridge, HardwareBridgeT, HardwareError, InternalControlIndex, + TempH, Value, +}; -pub struct WindowsBridge {} +pub struct WindowsBridge { + pub stream: TcpStream, +} const IP: &str = "127.0.0.1"; const DEFAULT_PORT: u16 = 55555; +impl HardwareBridge for WindowsBridge { + fn generate_hardware() -> (Hardware, HardwareBridgeT) { + let mut hardware = Hardware::default(); + + let stream = try_connect(); + + let mut data = String::new(); + let mut buf_reader = BufReader::new(&stream); + buf_reader.read_line(&mut data).unwrap(); + let base_hardware_list = serde_json::from_str::>(&data).unwrap(); + + for base_hardware in base_hardware_list { + match base_hardware.hardware_type { + HardwareType::Control => hardware.controls.push(Rc::new(ControlH { + name: base_hardware.name, + hardware_id: base_hardware.id, + info: String::new(), + internal_index: base_hardware.index, + })), + HardwareType::Fan => hardware.fans.push(Rc::new(FanH { + name: base_hardware.name, + hardware_id: base_hardware.id, + info: String::new(), + internal_index: base_hardware.index, + })), + HardwareType::Temp => hardware.temps.push(Rc::new(TempH { + name: base_hardware.name, + hardware_id: base_hardware.id, + info: String::new(), + internal_index: base_hardware.index, + })), + } + } + + let windows_bridge = WindowsBridge { stream }; + + (hardware, Box::new(windows_bridge)) + } + + fn get_value(&mut self, internal_index: &usize) -> Result { + info!("send command: {:?}", Command::GetValue); + + let command: &[u8; 4] = &From::from(Command::GetValue); + self.stream.write_all(command).unwrap(); + + info!("send index: {}", internal_index); + let index: &[u8; 4] = &From::from(I32(*internal_index)); + self.stream.write_all(index).unwrap(); + + info!("read value ..."); + let mut buf = [0u8; 4]; + self.stream.read_exact(&mut buf).unwrap(); + info!("read value!"); + + let i32 = I32::from(buf); + Ok(i32.0) + } + + fn set_value(&mut self, internal_index: &usize, value: Value) -> Result<(), HardwareError> { + todo!() + } + + fn set_mode(&mut self, internal_index: &usize, value: Value) -> Result<(), HardwareError> { + todo!() + } +} + +fn try_connect() -> TcpStream { + for port in DEFAULT_PORT..65535 { + match TcpStream::connect((IP, port)) { + Ok(stream) => { + info!("connected to {}:{}", IP, port); + return stream; + } + Err(_) => continue, + } + } + panic!("can't find connection") +} + #[derive(Deserialize, Debug, Clone)] enum HardwareType { - Control, - Fan, - Temp, + Control = 1, + Fan = 2, + Temp = 3, +} + +#[derive(Debug, Clone)] +#[repr(i32)] +enum Command { + SetAuto = 1, + SetValue = 2, + GetValue = 3, + Shutdown = 4, +} + +impl From for [u8; 4] { + #[inline] + fn from(command: Command) -> Self { + let command_value = command as u32; + if is_little_endian() { + command_value.to_le_bytes() + } else { + command_value.to_be_bytes() + } + } +} + +struct I32(T); + +impl From<[u8; 4]> for I32 { + #[inline] + fn from(bytes: [u8; 4]) -> Self { + if is_little_endian() { + I32(i32::from_le_bytes(bytes)) + } else { + I32(i32::from_be_bytes(bytes)) + } + } +} + +impl From> for [u8; 4] { + #[inline] + fn from(number: I32) -> Self { + let index = number.0 as i32; + if is_little_endian() { + index.to_le_bytes() + } else { + index.to_be_bytes() + } + } } #[derive(Deserialize, Debug, Clone)] @@ -28,29 +163,31 @@ struct BaseHardware { hardware_type: HardwareType, } -impl HardwareBridge for WindowsBridge { - fn generate_hardware() -> Hardware { - let hardware = Hardware::default(); - - let mut stream = try_connect(); - println!("Connected to the server!"); - - let mut data = String::new(); - stream.read_to_string(&mut data).unwrap(); - let base_hardware_list = serde_json::from_str::>(&data).unwrap(); +#[derive(Debug)] +struct InternalSensor { + index: usize, +} - dbg!(&base_hardware_list); +#[derive(Debug)] +struct InternalControl { + index: usize, +} - hardware +impl Drop for InternalControl { + fn drop(&mut self) { + info!("pwm sould be set to auto"); + // TODO: set to auto } } -fn try_connect() -> TcpStream { - for port in DEFAULT_PORT..65535 { - match TcpStream::connect((IP, port)) { - Ok(stream) => return stream, - Err(_) => continue, - } - } - panic!("can't find connection") +#[inline] +fn is_little_endian() -> bool { + let test_value: u16 = 1; + let test_ptr: *const u16 = &test_value; + + // Read the first byte of the u16 through the pointer + let byte = unsafe { *test_ptr as u8 }; + + // If the byte is 1, the system is little-endian; otherwise, it's big-endian + byte == 1 } diff --git a/src/integrated_test.rs b/src/integrated_test.rs index 92db6775..bf3f9fb7 100644 --- a/src/integrated_test.rs +++ b/src/integrated_test.rs @@ -5,7 +5,7 @@ use std::time::Duration; use data::directories::DirManager; use data::{config::Config, node::AppGraph, update::Update, AppState}; -use hardware::{hardware_test, HardwareBridge}; +use hardware::{fake_hardware, HardwareBridge}; #[test] fn test_config() { @@ -14,7 +14,7 @@ fn test_config() { let dir_manager = DirManager::new(Some(PathBuf::from("./.config"))); let settings = dir_manager.init_settings(); - let hardware = hardware_test::TestBridge::generate_hardware(); + let hardware = fake_hardware::FakeHardwareBridge::generate_hardware(); DirManager::serialize(&dir_manager.hardware_file_path(), &hardware).unwrap(); let config = DirManager::deserialize::( diff --git a/src/main.rs b/src/main.rs index afea8bf7..afab1863 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,13 +21,13 @@ fn main() { let settings = dir_manager.init_settings(); #[cfg(feature = "fake_hardware")] - let hardware = hardware::hardware_test::TestBridge::generate_hardware(); + let hardware = hardware::fake_hardware::FakeHardwareBridge::generate_hardware(); #[cfg(all(not(feature = "fake_hardware"), target_os = "linux"))] - let hardware = hardware::linux::LinuxBridge::generate_hardware(); + let (hardware, bridge) = hardware::linux::LinuxBridge::generate_hardware(); #[cfg(all(not(feature = "fake_hardware"), target_os = "windows"))] - let hardware = hardware::windows::WindowsBridge::generate_hardware(); + let (hardware, bridge) = hardware::windows::WindowsBridge::generate_hardware(); let hardware_file_path = dir_manager.hardware_file_path(); @@ -51,6 +51,7 @@ fn main() { dir_manager, settings, hardware, + bridge, app_graph, update: Update::new(), }; diff --git a/ui/src/lib.rs b/ui/src/lib.rs index a2b2c243..374ac462 100644 --- a/ui/src/lib.rs +++ b/ui/src/lib.rs @@ -70,6 +70,7 @@ impl Application for Ui { match self.app_state.update.graph( &mut self.app_state.app_graph.nodes, &self.app_state.app_graph.root_nodes, + &mut self.app_state.bridge, ) { Ok(_) => {} Err(e) => {