1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// temperature.rs

use byteorder::ByteOrder;
use ctl_error::SysctlError;
use ctl_info::CtlInfo;
use ctl_type::CtlType;
use ctl_value::CtlValue;

use std::f32;

/// A custom type for temperature sysctls.
///
/// # Example
/// ```
/// # extern crate sysctl;
/// # use sysctl::Sysctl;
/// let ctl = sysctl::Ctl::new("dev.cpu.0.temperature").unwrap();
/// if let Ok(sysctl::CtlValue::Temperature(val)) = ctl.value() {
///     println!("Temperature: {:.2}K, {:.2}F, {:.2}C",
///               val.kelvin(),
///               val.fahrenheit(),
///               val.celsius());
/// } else {
///     panic!("Error, not a temperature ctl!")
/// }
/// ```
/// Not available on MacOS
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub struct Temperature {
    value: f32, // Kelvin
}
impl Temperature {
    pub fn kelvin(&self) -> f32 {
        self.value
    }
    pub fn celsius(&self) -> f32 {
        self.value - 273.15
    }
    pub fn fahrenheit(&self) -> f32 {
        1.8 * self.celsius() + 32.0
    }
}

pub fn temperature(info: &CtlInfo, val: &Vec<u8>) -> Result<CtlValue, SysctlError> {
    let prec: u32 = {
        match info.fmt.len() {
            l if l > 2 => match info.fmt[2..3].parse::<u32>() {
                Ok(x) if x <= 9 => x,
                _ => 1,
            },
            _ => 1,
        }
    };

    let base = 10u32.pow(prec) as f32;

    let make_temp = move |f: f32| -> Result<CtlValue, SysctlError> {
        Ok(CtlValue::Temperature(Temperature { value: f / base }))
    };

    match info.ctl_type {
        CtlType::Int => make_temp(byteorder::LittleEndian::read_i32(&val) as f32),
        CtlType::S64 => make_temp(byteorder::LittleEndian::read_u64(&val) as f32),
        CtlType::Uint => make_temp(byteorder::LittleEndian::read_u32(&val) as f32),
        CtlType::Long => make_temp(byteorder::LittleEndian::read_i64(&val) as f32),
        CtlType::Ulong => make_temp(byteorder::LittleEndian::read_u64(&val) as f32),
        CtlType::U64 => make_temp(byteorder::LittleEndian::read_u64(&val) as f32),
        CtlType::U8 => make_temp(val[0] as u8 as f32),
        CtlType::U16 => make_temp(byteorder::LittleEndian::read_u16(&val) as f32),
        CtlType::S8 => make_temp(val[0] as i8 as f32),
        CtlType::S16 => make_temp(byteorder::LittleEndian::read_i16(&val) as f32),
        CtlType::S32 => make_temp(byteorder::LittleEndian::read_i32(&val) as f32),
        CtlType::U32 => make_temp(byteorder::LittleEndian::read_u32(&val) as f32),
        _ => Err(SysctlError::UnknownType),
    }
}

#[cfg(all(test, target_os = "freebsd"))]
mod tests_freebsd {
    use byteorder::WriteBytesExt;

    #[test]
    fn ctl_temperature_ik() {
        let info = crate::CtlInfo {
            ctl_type: crate::CtlType::Int,
            fmt: "IK".into(),
            flags: 0,
        };
        let mut val = vec![];
        // Default value (IK) in deciKelvin integer
        val.write_i32::<byteorder::LittleEndian>(3330)
            .expect("Error parsing value to byte array");

        let t = super::temperature(&info, &val).unwrap();
        if let crate::CtlValue::Temperature(tt) = t {
            assert!(tt.kelvin() - 333.0 < 0.1);
            assert!(tt.celsius() - 59.85 < 0.1);
            assert!(tt.fahrenheit() - 139.73 < 0.1);
        } else {
            assert!(false);
        }
    }

    #[test]
    fn ctl_temperature_ik3() {
        let info = crate::CtlInfo {
            ctl_type: crate::CtlType::Int,
            fmt: "IK3".into(),
            flags: 0,
        };
        let mut val = vec![];
        // Set value in milliKelvin
        val.write_i32::<byteorder::LittleEndian>(333000)
            .expect("Error parsing value to byte array");

        let t = super::temperature(&info, &val).unwrap();
        if let crate::CtlValue::Temperature(tt) = t {
            assert!(tt.kelvin() - 333.0 < 0.1);
        } else {
            assert!(false);
        }
    }

}