[go: up one dir, main page]

sysctl/
temperature.rs

1// temperature.rs
2
3use byteorder::ByteOrder;
4use ctl_error::SysctlError;
5use ctl_info::CtlInfo;
6use ctl_type::CtlType;
7use ctl_value::CtlValue;
8
9use std::f32;
10
11/// A custom type for temperature sysctls.
12///
13/// # Example
14/// ```
15/// # use sysctl::Sysctl;
16/// if let Ok(ctl) = sysctl::Ctl::new("dev.cpu.0.temperature") {
17///     let val = ctl.value().unwrap();
18///     let temp = val.as_temperature().unwrap();
19///     println!("Temperature: {:.2}K, {:.2}F, {:.2}C",
20///               temp.kelvin(),
21///               temp.fahrenheit(),
22///               temp.celsius());
23/// }
24/// ```
25/// Not available on MacOS
26#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
27pub struct Temperature {
28    value: f32, // Kelvin
29}
30impl Temperature {
31    pub fn kelvin(&self) -> f32 {
32        self.value
33    }
34    pub fn celsius(&self) -> f32 {
35        self.value - 273.15
36    }
37    pub fn fahrenheit(&self) -> f32 {
38        1.8 * self.celsius() + 32.0
39    }
40}
41
42pub fn temperature(info: &CtlInfo, val: &[u8]) -> Result<CtlValue, SysctlError> {
43    let prec: u32 = {
44        match info.fmt.len() {
45            l if l > 2 => match info.fmt[2..3].parse::<u32>() {
46                Ok(x) if x <= 9 => x,
47                _ => 1,
48            },
49            _ => 1,
50        }
51    };
52
53    let base = 10u32.pow(prec) as f32;
54
55    let make_temp = move |f: f32| -> Result<CtlValue, SysctlError> {
56        Ok(CtlValue::Temperature(Temperature { value: f / base }))
57    };
58
59    match info.ctl_type {
60        CtlType::Int => make_temp(byteorder::LittleEndian::read_i32(&val) as f32),
61        CtlType::S64 => make_temp(byteorder::LittleEndian::read_i64(&val) as f32),
62        CtlType::Uint => make_temp(byteorder::LittleEndian::read_u32(&val) as f32),
63        CtlType::Long => make_temp(byteorder::LittleEndian::read_i64(&val) as f32),
64        CtlType::Ulong => make_temp(byteorder::LittleEndian::read_u64(&val) as f32),
65        CtlType::U64 => make_temp(byteorder::LittleEndian::read_u64(&val) as f32),
66        CtlType::U8 => make_temp(val[0] as u8 as f32),
67        CtlType::U16 => make_temp(byteorder::LittleEndian::read_u16(&val) as f32),
68        CtlType::S8 => make_temp(val[0] as i8 as f32),
69        CtlType::S16 => make_temp(byteorder::LittleEndian::read_i16(&val) as f32),
70        CtlType::S32 => make_temp(byteorder::LittleEndian::read_i32(&val) as f32),
71        CtlType::U32 => make_temp(byteorder::LittleEndian::read_u32(&val) as f32),
72        _ => Err(SysctlError::UnknownType),
73    }
74}
75
76#[cfg(all(test, target_os = "freebsd"))]
77mod tests_freebsd {
78    use byteorder::WriteBytesExt;
79
80    #[test]
81    fn ctl_temperature_ik() {
82        let info = crate::CtlInfo {
83            ctl_type: crate::CtlType::Int,
84            fmt: "IK".into(),
85            flags: 0,
86        };
87        let mut val = vec![];
88        // Default value (IK) in deciKelvin integer
89        val.write_i32::<byteorder::LittleEndian>(3330)
90            .expect("Error parsing value to byte array");
91
92        let t = super::temperature(&info, &val).unwrap();
93        let tt = t.as_temperature().unwrap();
94        assert!(tt.kelvin() - 333.0 < 0.1);
95        assert!(tt.celsius() - 59.85 < 0.1);
96        assert!(tt.fahrenheit() - 139.73 < 0.1);
97    }
98
99    #[test]
100    fn ctl_temperature_ik3() {
101        let info = crate::CtlInfo {
102            ctl_type: crate::CtlType::Int,
103            fmt: "IK3".into(),
104            flags: 0,
105        };
106        let mut val = vec![];
107        // Set value in milliKelvin
108        val.write_i32::<byteorder::LittleEndian>(333000)
109            .expect("Error parsing value to byte array");
110
111        let t = super::temperature(&info, &val).unwrap();
112        let tt = t.as_temperature().unwrap();
113        assert!(tt.kelvin() - 333.0 < 0.1);
114    }
115}