mod helper_functions;
mod iterator;
use super::error::{Error, Result};
use helper_functions::*;
pub use iterator::{Iter, NamedIter};
use crate::parsing::{Error as ParsingError, Result as ParsingResult};
use crate::sensors::sync_sensors::{
curr::*, energy::*, fan::*, humidity::*, intrusion::*, power::*, pwm::*, temp::*, voltage::*,
};
use crate::units::Raw;
use std::{
cmp::Ordering,
collections::BTreeMap,
fmt::Debug,
fs::read_to_string,
io::ErrorKind as IoErrorKind,
path::{Path, PathBuf},
time::Duration,
};
#[derive(Debug, Clone)]
pub struct Hwmon {
name: String,
label: Option<String>,
path: PathBuf,
index: u16,
currents: BTreeMap<u16, CurrentSensorStruct>,
energies: BTreeMap<u16, EnergySensorStruct>,
fans: BTreeMap<u16, FanSensorStruct>,
humidities: BTreeMap<u16, HumiditySensorStruct>,
intrusions: BTreeMap<u16, IntrusionSensorStruct>,
powers: BTreeMap<u16, PowerSensorStruct>,
pwms: BTreeMap<u16, PwmSensorStruct>,
temps: BTreeMap<u16, TempSensorStruct>,
voltages: BTreeMap<u16, VoltageSensorStruct>,
}
impl Hwmon {
pub fn name(&self) -> &str {
&self.name
}
pub fn label(&self) -> Option<&str> {
self.label.as_deref()
}
pub fn path(&self) -> &Path {
&self.path
}
pub fn index(&self) -> u16 {
self.index
}
pub fn device_path(&self) -> PathBuf {
self.path().join("device").canonicalize().unwrap()
}
pub fn update_interval(&self) -> Result<Duration> {
let path = self.path().join("update_interval");
match read_to_string(&path) {
Ok(s) => Duration::from_raw(&s).map_err(|e| Error::unit(e, path)),
Err(e) => {
if e.kind() == IoErrorKind::NotFound {
Err(Error::update_interval_not_available())
} else {
Err(Error::io(e, path))
}
}
}
}
pub fn beep_enable(&self) -> Result<bool> {
let path = self.path().join("beep_enable");
match read_to_string(&path) {
Ok(s) => bool::from_raw(&s).map_err(|e| Error::unit(e, path)),
Err(e) => {
if e.kind() == IoErrorKind::NotFound {
Err(Error::beep_enable())
} else {
Err(Error::io(e, path))
}
}
}
}
pub fn currents(&self) -> &BTreeMap<u16, impl CurrentSensor + Clone + Send + Sync + 'static> {
&self.currents
}
pub fn energies(&self) -> &BTreeMap<u16, impl EnergySensor + Clone + Send + Sync + 'static> {
&self.energies
}
pub fn fans(&self) -> &BTreeMap<u16, impl FanSensor + Clone + Send + Sync + 'static> {
&self.fans
}
pub fn humidities(
&self,
) -> &BTreeMap<u16, impl HumiditySensor + Clone + Send + Sync + 'static> {
&self.humidities
}
pub fn intrusions(
&self,
) -> &BTreeMap<u16, impl IntrusionSensor + Clone + Send + Sync + 'static> {
&self.intrusions
}
pub fn powers(&self) -> &BTreeMap<u16, impl PowerSensor + Clone + Send + Sync + 'static> {
&self.powers
}
pub fn pwms(&self) -> &BTreeMap<u16, impl PwmSensor + Clone + Send + Sync + 'static> {
&self.pwms
}
pub fn temps(&self) -> &BTreeMap<u16, impl TempSensor + Clone + Send + Sync + 'static> {
&self.temps
}
pub fn voltages(&self) -> &BTreeMap<u16, impl VoltageSensor + Clone + Send + Sync + 'static> {
&self.voltages
}
pub fn current(
&self,
index: u16,
) -> Option<&(impl CurrentSensor + Clone + Send + Sync + 'static)> {
self.currents.get(&index)
}
pub fn energy(
&self,
index: u16,
) -> Option<&(impl EnergySensor + Clone + Send + Sync + 'static)> {
self.energies.get(&index)
}
pub fn fan(&self, index: u16) -> Option<&(impl FanSensor + Clone + Send + Sync + 'static)> {
self.fans.get(&index)
}
pub fn humidity(
&self,
index: u16,
) -> Option<&(impl HumiditySensor + Clone + Send + Sync + 'static)> {
self.humidities.get(&index)
}
pub fn intrusion(
&self,
index: u16,
) -> Option<&(impl IntrusionSensor + Clone + Send + Sync + 'static)> {
self.intrusions.get(&index)
}
pub fn power(&self, index: u16) -> Option<&(impl PowerSensor + Clone + Send + Sync + 'static)> {
self.powers.get(&index)
}
pub fn pwm(&self, index: u16) -> Option<&(impl PwmSensor + Clone + Send + Sync + 'static)> {
self.pwms.get(&index)
}
pub fn temp(&self, index: u16) -> Option<&(impl TempSensor + Clone + Send + Sync + 'static)> {
self.temps.get(&index)
}
pub fn voltage(
&self,
index: u16,
) -> Option<&(impl VoltageSensor + Clone + Send + Sync + 'static)> {
self.voltages.get(&index)
}
pub(crate) fn try_from_path(path: impl Into<PathBuf>, index: u16) -> ParsingResult<Self> {
let path = path.into();
check_path(&path)?;
let mut hwmon = Self {
name: get_name(&path)?,
label: get_label(&path).ok(),
path,
index,
currents: BTreeMap::new(),
energies: BTreeMap::new(),
fans: BTreeMap::new(),
humidities: BTreeMap::new(),
intrusions: BTreeMap::new(),
powers: BTreeMap::new(),
pwms: BTreeMap::new(),
temps: BTreeMap::new(),
voltages: BTreeMap::new(),
};
hwmon.currents = init_sensors(&hwmon, 1)?;
hwmon.energies = init_sensors(&hwmon, 1)?;
hwmon.fans = init_sensors(&hwmon, 1)?;
hwmon.humidities = init_sensors(&hwmon, 1)?;
hwmon.intrusions = init_sensors(&hwmon, 0)?;
hwmon.powers = init_sensors(&hwmon, 1)?;
hwmon.pwms = init_sensors(&hwmon, 1)?;
hwmon.temps = init_sensors(&hwmon, 1)?;
hwmon.voltages = init_sensors(&hwmon, 0)?;
Ok(hwmon)
}
}
#[cfg(feature = "writeable")]
impl Hwmon {
pub fn set_update_interval(&self, interval: Duration) -> Result<()> {
let path = self.path().join("update_interval");
match std::fs::write(&path, interval.to_raw().as_bytes()) {
Ok(_) => Ok(()),
Err(e) => match e.kind() {
IoErrorKind::NotFound => Err(Error::update_interval_not_available()),
IoErrorKind::PermissionDenied => Err(Error::insufficient_rights(path)),
_ => Err(Error::io(e, path)),
},
}
}
pub fn set_beep_enable(&self, beep_enable: bool) -> Result<()> {
let path = self.path().join("beep_enable");
match std::fs::write(&path, beep_enable.to_raw().as_bytes()) {
Ok(_) => Ok(()),
Err(e) => match e.kind() {
IoErrorKind::NotFound => Err(Error::beep_enable()),
IoErrorKind::PermissionDenied => Err(Error::insufficient_rights(path)),
_ => Err(Error::io(e, path)),
},
}
}
pub fn writeable_currents(
&self,
) -> &BTreeMap<u16, impl WriteableCurrentSensor + Clone + Send + Sync + 'static> {
&self.currents
}
pub fn writeable_energies(
&self,
) -> &BTreeMap<u16, impl WriteableEnergySensor + Clone + Send + Sync + 'static> {
&self.energies
}
pub fn writeable_fans(
&self,
) -> &BTreeMap<u16, impl WriteableFanSensor + Clone + Send + Sync + 'static> {
&self.fans
}
pub fn writeable_humidities(
&self,
) -> &BTreeMap<u16, impl WriteableHumiditySensor + Clone + Send + Sync + 'static> {
&self.humidities
}
pub fn writeable_intrusions(
&self,
) -> &BTreeMap<u16, impl WriteableIntrusionSensor + Clone + Send + Sync + 'static> {
&self.intrusions
}
pub fn writeable_powers(
&self,
) -> &BTreeMap<u16, impl WriteablePowerSensor + Clone + Send + Sync + 'static> {
&self.powers
}
pub fn writeable_pwms(
&self,
) -> &BTreeMap<u16, impl WriteablePwmSensor + Clone + Send + Sync + 'static> {
&self.pwms
}
pub fn writeable_temps(
&self,
) -> &BTreeMap<u16, impl WriteableTempSensor + Clone + Send + Sync + 'static> {
&self.temps
}
pub fn writeable_voltages(
&self,
) -> &BTreeMap<u16, impl WriteableVoltageSensor + Clone + Send + Sync + 'static> {
&self.voltages
}
pub fn writeable_current(
&self,
index: u16,
) -> Option<&(impl WriteableCurrentSensor + Clone + Send + Sync + 'static)> {
self.currents.get(&index)
}
pub fn writeable_energy(
&self,
index: u16,
) -> Option<&(impl WriteableEnergySensor + Clone + Send + Sync + 'static)> {
self.energies.get(&index)
}
pub fn writeable_fan(
&self,
index: u16,
) -> Option<&(impl WriteableFanSensor + Clone + Send + Sync + 'static)> {
self.fans.get(&index)
}
pub fn writeable_humidity(
&self,
index: u16,
) -> Option<&(impl WriteableHumiditySensor + Clone + Send + Sync + 'static)> {
self.humidities.get(&index)
}
pub fn writeable_intrusion(
&self,
index: u16,
) -> Option<&(impl WriteableIntrusionSensor + Clone + Send + Sync + 'static)> {
self.intrusions.get(&index)
}
pub fn writeable_power(
&self,
index: u16,
) -> Option<&(impl WriteablePowerSensor + Clone + Send + Sync + 'static)> {
self.powers.get(&index)
}
pub fn writeable_pwm(
&self,
index: u16,
) -> Option<&(impl WriteablePwmSensor + Clone + Send + Sync + 'static)> {
self.pwms.get(&index)
}
pub fn writeable_temp(
&self,
index: u16,
) -> Option<&(impl WriteableTempSensor + Clone + Send + Sync + 'static)> {
self.temps.get(&index)
}
pub fn writeable_voltage(
&self,
index: u16,
) -> Option<&(impl WriteableVoltageSensor + Clone + Send + Sync + 'static)> {
self.voltages.get(&index)
}
}
impl PartialEq for Hwmon {
fn eq(&self, other: &Self) -> bool {
self.path.eq(other.path())
}
}
impl Eq for Hwmon {}
impl PartialOrd for Hwmon {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Hwmon {
fn cmp(&self, other: &Self) -> Ordering {
self.path.cmp(&other.path)
}
}
#[derive(Debug, Clone)]
pub struct Hwmons {
#[cfg(feature = "unrestricted_parsing")]
path: PathBuf,
hwmons: BTreeMap<u16, Hwmon>,
}
impl Hwmons {
pub fn parse() -> ParsingResult<Self> {
Self::parse_path("/sys/class/hwmon/")
}
pub fn hwmons_by_name<N: AsRef<str>>(&self, name: N) -> NamedIter<'_, N> {
NamedIter::new(self.iter(), name)
}
pub fn hwmon_by_index(&self, index: u16) -> Option<&Hwmon> {
self.hwmons.get(&index)
}
pub fn hwmon_by_device_path(&self, device_path: impl AsRef<Path>) -> Option<&Hwmon> {
self.hwmons
.values()
.find(move |&hwmon| hwmon.device_path() == device_path.as_ref())
}
pub fn iter(&self) -> Iter<'_> {
Iter::new(self.hwmons.iter())
}
#[cfg(feature = "unrestricted_parsing")]
pub fn parse_unrestricted(path: impl AsRef<Path>) -> ParsingResult<Self> {
Self::parse_path(path)
}
#[cfg(feature = "unrestricted_parsing")]
pub fn path(&self) -> &Path {
&self.path
}
pub(crate) fn parse_path(path: impl AsRef<Path>) -> ParsingResult<Self> {
let path = path.as_ref();
let mut hwmons = Hwmons {
#[cfg(feature = "unrestricted_parsing")]
path: path.to_path_buf(),
hwmons: BTreeMap::new(),
};
let mut index;
for entry in path.read_dir().map_err(|e| ParsingError::hwmons(e, path))? {
let entry = entry.map_err(|e| ParsingError::hwmons(e, path))?;
let entry_path = entry.path();
if !entry_path.is_dir() {
continue;
}
let file_name = entry.file_name();
if let Some(index_str) = file_name.to_string_lossy().strip_prefix("hwmon") {
index = index_str
.parse()
.map_err(|e| ParsingError::hwmon_index(e, &entry_path))?;
} else {
continue;
}
hwmons
.hwmons
.insert(index, Hwmon::try_from_path(entry_path, index)?);
}
Ok(hwmons)
}
}
#[cfg(test)]
mod tests;