Merge pull request #9 from BoostCookie/main
Fanspeeds as floats, 0 is lowest speed, bugfixes
This commit is contained in:
commit
ac1daf69ea
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1,7 +1,5 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "0.7.18"
|
version = "0.7.18"
|
||||||
|
16
README.md
16
README.md
@ -35,35 +35,35 @@ cards = ["card0"]
|
|||||||
|
|
||||||
[[speed_matrix]]
|
[[speed_matrix]]
|
||||||
temp = 4.0
|
temp = 4.0
|
||||||
speed = 4
|
speed = 4.0
|
||||||
|
|
||||||
[[speed_matrix]]
|
[[speed_matrix]]
|
||||||
temp = 30.0
|
temp = 30.0
|
||||||
speed = 33
|
speed = 33.0
|
||||||
|
|
||||||
[[speed_matrix]]
|
[[speed_matrix]]
|
||||||
temp = 45.0
|
temp = 45.0
|
||||||
speed = 50
|
speed = 50.0
|
||||||
|
|
||||||
[[speed_matrix]]
|
[[speed_matrix]]
|
||||||
temp = 60.0
|
temp = 60.0
|
||||||
speed = 66
|
speed = 66.0
|
||||||
|
|
||||||
[[speed_matrix]]
|
[[speed_matrix]]
|
||||||
temp = 65.0
|
temp = 65.0
|
||||||
speed = 69
|
speed = 69.0
|
||||||
|
|
||||||
[[speed_matrix]]
|
[[speed_matrix]]
|
||||||
temp = 70.0
|
temp = 70.0
|
||||||
speed = 75
|
speed = 75.0
|
||||||
|
|
||||||
[[speed_matrix]]
|
[[speed_matrix]]
|
||||||
temp = 75.0
|
temp = 75.0
|
||||||
speed = 89
|
speed = 89.0
|
||||||
|
|
||||||
[[speed_matrix]]
|
[[speed_matrix]]
|
||||||
temp = 80.0
|
temp = 80.0
|
||||||
speed = 100
|
speed = 100.0
|
||||||
```
|
```
|
||||||
|
|
||||||
## :bookmark: License
|
## :bookmark: License
|
||||||
|
@ -87,7 +87,7 @@ impl Serialize for Card {
|
|||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct MatrixPoint {
|
pub struct MatrixPoint {
|
||||||
pub temp: f64,
|
pub temp: f64,
|
||||||
pub speed: u32,
|
pub speed: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
|
||||||
@ -131,54 +131,29 @@ impl Config {
|
|||||||
&self.cards
|
&self.cards
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn speed_for_temp(&self, temp: f64) -> u32 {
|
pub fn speed_for_temp(&self, temp: f64) -> f64 {
|
||||||
let idx = match self.speed_matrix.iter().rposition(|p| p.temp <= temp) {
|
let idx = match self.speed_matrix.iter().rposition(|p| p.temp <= temp) {
|
||||||
Some(idx) => idx,
|
Some(idx) => idx,
|
||||||
_ => return 4,
|
_ => return self.min_speed(),
|
||||||
};
|
};
|
||||||
|
|
||||||
match (idx, self.speed_matrix.len() - 1) {
|
if idx == self.speed_matrix.len() - 1 {
|
||||||
(0, _) => self.min_speed(),
|
return self.max_speed();
|
||||||
(current, max) if current == max => self.max_speed(),
|
|
||||||
_ => {
|
|
||||||
if self.is_exact_point(idx, temp) {
|
|
||||||
return self.speed_matrix.get(idx).map(|p| p.speed).unwrap_or(4);
|
|
||||||
}
|
|
||||||
let max = match self.speed_matrix.get(idx + 1) {
|
|
||||||
Some(p) => p,
|
|
||||||
_ => return 4,
|
|
||||||
};
|
|
||||||
let min = match self.speed_matrix.get(idx) {
|
|
||||||
Some(p) => p,
|
|
||||||
_ => return 4,
|
|
||||||
};
|
|
||||||
let speed_diff = max.speed as f64 - min.speed as f64;
|
|
||||||
let temp_diff = max.temp as f64 - min.temp as f64;
|
|
||||||
let increase_by =
|
|
||||||
(((temp as f64 - min.temp as f64) / temp_diff) * speed_diff).round();
|
|
||||||
min.speed + increase_by as u32
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
crate::linear_map(temp, self.speed_matrix[idx].temp, self.speed_matrix[idx+1].temp, self.speed_matrix[idx].speed, self.speed_matrix[idx+1].speed)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn log_level(&self) -> LogLevel {
|
pub fn log_level(&self) -> LogLevel {
|
||||||
self.log_level
|
self.log_level
|
||||||
}
|
}
|
||||||
|
|
||||||
fn min_speed(&self) -> u32 {
|
fn min_speed(&self) -> f64 {
|
||||||
self.speed_matrix.first().map(|p| p.speed).unwrap_or(4)
|
self.speed_matrix.first().map(|p| p.speed).unwrap_or(0f64)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn max_speed(&self) -> u32 {
|
fn max_speed(&self) -> f64 {
|
||||||
self.speed_matrix.last().map(|p| p.speed).unwrap_or(100)
|
self.speed_matrix.last().map(|p| p.speed).unwrap_or(100f64)
|
||||||
}
|
|
||||||
|
|
||||||
fn is_exact_point(&self, idx: usize, temp: f64) -> bool {
|
|
||||||
static DELTA: f64 = 0.001f64;
|
|
||||||
self.speed_matrix
|
|
||||||
.get(idx)
|
|
||||||
.map(|p| p.temp - DELTA < temp && p.temp + DELTA > temp)
|
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,35 +165,35 @@ impl Default for Config {
|
|||||||
speed_matrix: vec![
|
speed_matrix: vec![
|
||||||
MatrixPoint {
|
MatrixPoint {
|
||||||
temp: 4f64,
|
temp: 4f64,
|
||||||
speed: 4,
|
speed: 4f64,
|
||||||
},
|
},
|
||||||
MatrixPoint {
|
MatrixPoint {
|
||||||
temp: 30f64,
|
temp: 30f64,
|
||||||
speed: 33,
|
speed: 33f64,
|
||||||
},
|
},
|
||||||
MatrixPoint {
|
MatrixPoint {
|
||||||
temp: 45f64,
|
temp: 45f64,
|
||||||
speed: 50,
|
speed: 50f64,
|
||||||
},
|
},
|
||||||
MatrixPoint {
|
MatrixPoint {
|
||||||
temp: 60f64,
|
temp: 60f64,
|
||||||
speed: 66,
|
speed: 66f64,
|
||||||
},
|
},
|
||||||
MatrixPoint {
|
MatrixPoint {
|
||||||
temp: 65f64,
|
temp: 65f64,
|
||||||
speed: 69,
|
speed: 69f64,
|
||||||
},
|
},
|
||||||
MatrixPoint {
|
MatrixPoint {
|
||||||
temp: 70f64,
|
temp: 70f64,
|
||||||
speed: 75,
|
speed: 75f64,
|
||||||
},
|
},
|
||||||
MatrixPoint {
|
MatrixPoint {
|
||||||
temp: 75f64,
|
temp: 75f64,
|
||||||
speed: 89,
|
speed: 89f64,
|
||||||
},
|
},
|
||||||
MatrixPoint {
|
MatrixPoint {
|
||||||
temp: 80f64,
|
temp: 80f64,
|
||||||
speed: 100,
|
speed: 100f64,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
@ -239,24 +214,15 @@ pub fn load_config() -> std::io::Result<Config> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if config.speed_matrix.iter().fold(
|
|
||||||
1000,
|
|
||||||
|n, point| if point.speed < n { point.speed } else { n },
|
|
||||||
) < 4
|
|
||||||
{
|
|
||||||
log::error!("Due to driver bug lowest fan speed must be greater or equal 4");
|
|
||||||
return Err(std::io::Error::from(ErrorKind::InvalidData));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut last_point: Option<&MatrixPoint> = None;
|
let mut last_point: Option<&MatrixPoint> = None;
|
||||||
|
|
||||||
for matrix_point in config.speed_matrix.iter() {
|
for matrix_point in config.speed_matrix.iter() {
|
||||||
if matrix_point.speed <= 0 {
|
if matrix_point.speed < 0f64 {
|
||||||
log::error!("Fan speed can's be below 0 found {}", matrix_point.speed);
|
log::error!("Fan speed can't be below 0.0 found {}", matrix_point.speed);
|
||||||
return Err(std::io::Error::from(ErrorKind::InvalidData));
|
return Err(std::io::Error::from(ErrorKind::InvalidData));
|
||||||
}
|
}
|
||||||
if matrix_point.speed > 100 {
|
if matrix_point.speed > 100f64 {
|
||||||
log::error!("Fan speed can's be above 100 found {}", matrix_point.speed);
|
log::error!("Fan speed can't be above 100.0 found {}", matrix_point.speed);
|
||||||
return Err(std::io::Error::from(ErrorKind::InvalidData));
|
return Err(std::io::Error::from(ErrorKind::InvalidData));
|
||||||
}
|
}
|
||||||
if let Some(last_point) = last_point {
|
if let Some(last_point) = last_point {
|
||||||
@ -317,13 +283,13 @@ mod speed_for_temp {
|
|||||||
#[test]
|
#[test]
|
||||||
fn below_minimal() {
|
fn below_minimal() {
|
||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
assert_eq!(config.speed_for_temp(1f64), 4);
|
assert_eq!(config.speed_for_temp(1f64), 4f64);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn minimal() {
|
fn minimal() {
|
||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
assert_eq!(config.speed_for_temp(4f64), 4);
|
assert_eq!(config.speed_for_temp(4f64), 4f64);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -331,7 +297,7 @@ mod speed_for_temp {
|
|||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
// 45 -> 50
|
// 45 -> 50
|
||||||
// 60 -> 66
|
// 60 -> 66
|
||||||
assert_eq!(config.speed_for_temp(46f64), 51);
|
assert_eq!(config.speed_for_temp(46f64).round(), 51f64);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -339,7 +305,7 @@ mod speed_for_temp {
|
|||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
// 45 -> 50
|
// 45 -> 50
|
||||||
// 60 -> 66
|
// 60 -> 66
|
||||||
assert_eq!(config.speed_for_temp(58f64), 64);
|
assert_eq!(config.speed_for_temp(58f64).round(), 64f64);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -347,24 +313,24 @@ mod speed_for_temp {
|
|||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
// 45 -> 50
|
// 45 -> 50
|
||||||
// 60 -> 66
|
// 60 -> 66
|
||||||
assert_eq!(config.speed_for_temp(59f64), 65);
|
assert_eq!(config.speed_for_temp(59f64).round(), 65f64);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn average() {
|
fn average() {
|
||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
assert_eq!(config.speed_for_temp(60f64), 66);
|
assert_eq!(config.speed_for_temp(60f64), 66f64);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn max() {
|
fn max() {
|
||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
assert_eq!(config.speed_for_temp(80f64), 100);
|
assert_eq!(config.speed_for_temp(80f64), 100f64);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn above_max() {
|
fn above_max() {
|
||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
assert_eq!(config.speed_for_temp(160f64), 100);
|
assert_eq!(config.speed_for_temp(160f64), 100f64);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
75
src/main.rs
75
src/main.rs
@ -21,12 +21,16 @@ pub enum AmdFanError {
|
|||||||
FailedReadVendor,
|
FailedReadVendor,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// linear mapping from the xrange to the yrange
|
||||||
|
fn linear_map(x: f64, x1: f64, x2: f64, y1: f64, y2: f64) -> f64 {
|
||||||
|
let m = (y2 - y1) / (x2 - x1);
|
||||||
|
m * (x - x1) + y1
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct HwMon {
|
pub struct HwMon {
|
||||||
card: Card,
|
card: Card,
|
||||||
name: String,
|
name: String,
|
||||||
fan_min: Option<u32>,
|
|
||||||
fan_max: Option<u32>,
|
|
||||||
pwm_min: Option<u32>,
|
pwm_min: Option<u32>,
|
||||||
pwm_max: Option<u32>,
|
pwm_max: Option<u32>,
|
||||||
}
|
}
|
||||||
@ -36,8 +40,6 @@ impl HwMon {
|
|||||||
Self {
|
Self {
|
||||||
card: card.clone(),
|
card: card.clone(),
|
||||||
name: String::from(name),
|
name: String::from(name),
|
||||||
fan_min: None,
|
|
||||||
fan_max: None,
|
|
||||||
pwm_min: None,
|
pwm_min: None,
|
||||||
pwm_max: None,
|
pwm_max: None,
|
||||||
}
|
}
|
||||||
@ -55,37 +57,6 @@ impl HwMon {
|
|||||||
self.read("name")
|
self.read("name")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fan_min(&mut self) -> u32 {
|
|
||||||
if self.fan_min.is_none() {
|
|
||||||
self.fan_min = Some(
|
|
||||||
self.read("fan1_min")
|
|
||||||
.unwrap_or_default()
|
|
||||||
.parse()
|
|
||||||
.unwrap_or(0),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
self.fan_min.unwrap_or_default()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fan_max(&mut self) -> u32 {
|
|
||||||
if self.fan_max.is_none() {
|
|
||||||
self.fan_max = Some(
|
|
||||||
self.read("fan1_max")
|
|
||||||
.unwrap_or_default()
|
|
||||||
.parse()
|
|
||||||
.unwrap_or(1500),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
self.fan_max.unwrap_or(1500)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fan_speed(&self) -> std::io::Result<u64> {
|
|
||||||
self.read("fan1_input")?.parse().map_err(|_e| {
|
|
||||||
log::warn!("Read from gpu monitor failed. Invalid fan speed");
|
|
||||||
std::io::Error::from(ErrorKind::InvalidInput)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pwm_min(&mut self) -> u32 {
|
pub fn pwm_min(&mut self) -> u32 {
|
||||||
if self.pwm_min.is_none() {
|
if self.pwm_min.is_none() {
|
||||||
self.pwm_min = Some(
|
self.pwm_min = Some(
|
||||||
@ -110,6 +81,13 @@ impl HwMon {
|
|||||||
self.pwm_max.unwrap_or(255)
|
self.pwm_max.unwrap_or(255)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pwm(&self) -> std::io::Result<u32> {
|
||||||
|
self.read("pwm1")?.parse().map_err(|_e| {
|
||||||
|
log::warn!("Read from gpu monitor failed. Invalid pwm value");
|
||||||
|
std::io::Error::from(ErrorKind::InvalidInput)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn pwm_speed(&self) -> std::io::Result<u64> {
|
pub fn pwm_speed(&self) -> std::io::Result<u64> {
|
||||||
self.read("pwm1")?.parse().map_err(|_e| {
|
self.read("pwm1")?.parse().map_err(|_e| {
|
||||||
log::warn!("Read from gpu monitor failed. Invalid fan speed");
|
log::warn!("Read from gpu monitor failed. Invalid fan speed");
|
||||||
@ -132,13 +110,7 @@ impl HwMon {
|
|||||||
pub fn is_amd(&self) -> bool {
|
pub fn is_amd(&self) -> bool {
|
||||||
std::fs::read_to_string(format!("{}/{}/device/vendor", ROOT_DIR, self.card))
|
std::fs::read_to_string(format!("{}/{}/device/vendor", ROOT_DIR, self.card))
|
||||||
.map_err(|_| AmdFanError::FailedReadVendor)
|
.map_err(|_| AmdFanError::FailedReadVendor)
|
||||||
.map(|vendor| {
|
.map(|vendor| vendor.trim() == "0x1002")
|
||||||
if vendor.trim() == "0x1002" {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,11 +122,18 @@ impl HwMon {
|
|||||||
self.write("pwm1_enable", 2)
|
self.write("pwm1_enable", 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_speed(&self, pwm: u64) -> std::io::Result<()> {
|
pub fn set_pwm(&self, value: u32) -> std::io::Result<()> {
|
||||||
if self.is_fan_automatic() {
|
if self.is_fan_automatic() {
|
||||||
self.set_manual()?;
|
self.set_manual()?;
|
||||||
}
|
}
|
||||||
self.write("pwm1", pwm)
|
self.write("pwm1", value as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_speed(&mut self, speed: f64) -> std::io::Result<()> {
|
||||||
|
let min = self.pwm_min() as f64;
|
||||||
|
let max = self.pwm_max() as f64;
|
||||||
|
let pwm = linear_map(speed, 0f64, 100f64, min, max).round() as u32;
|
||||||
|
self.set_pwm(pwm)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read(&self, name: &str) -> std::io::Result<String> {
|
fn read(&self, name: &str) -> std::io::Result<String> {
|
||||||
@ -329,7 +308,7 @@ fn service(config: Config) -> std::io::Result<()> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(e) = controller.hw_mon.set_speed(target_pwm as u64) {
|
if let Err(e) = controller.hw_mon.set_speed(target_pwm as f64) {
|
||||||
log::error!("Failed to change speed to {}. {:?}", target_pwm, e);
|
log::error!("Failed to change speed to {}. {:?}", target_pwm, e);
|
||||||
}
|
}
|
||||||
controller.last_temp = gpu_temp;
|
controller.last_temp = gpu_temp;
|
||||||
@ -384,9 +363,9 @@ fn monitor_cards(config: Config) -> std::io::Result<()> {
|
|||||||
println!(
|
println!(
|
||||||
" | {:>5.2} | {:>4} | {:>4} | {:>4} | {:>4} | {:>3}",
|
" | {:>5.2} | {:>4} | {:>4} | {:>4} | {:>4} | {:>3}",
|
||||||
card.hw_mon.gpu_temp().unwrap_or_default(),
|
card.hw_mon.gpu_temp().unwrap_or_default(),
|
||||||
card.hw_mon.fan_speed().unwrap_or_default(),
|
card.hw_mon.pwm_speed().unwrap_or_default(),
|
||||||
card.hw_mon.fan_min(),
|
card.hw_mon.pwm_min(),
|
||||||
card.hw_mon.fan_max(),
|
card.hw_mon.pwm_max(),
|
||||||
card.hw_mon.pwm_speed().unwrap_or_default(),
|
card.hw_mon.pwm_speed().unwrap_or_default(),
|
||||||
(card.hw_mon.pwm_speed().unwrap_or_default() as f32 / 2.55).round(),
|
(card.hw_mon.pwm_speed().unwrap_or_default() as f32 / 2.55).round(),
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user