#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
macro_rules! code_enum {
(
$(#[$meta:meta])*
pub enum $name:ident {
$( $(#[$vmeta:meta])* $variant:ident = $code:literal, )+
}
) => {
$(#[$meta])*
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[non_exhaustive]
pub enum $name {
#[default]
Unspecified,
$( $(#[$vmeta])* $variant, )+
Other(u8),
}
impl From<u8> for $name {
fn from(code: u8) -> Self {
match code {
0 => Self::Unspecified,
$( $code => Self::$variant, )+
other => Self::Other(other),
}
}
}
impl From<$name> for u8 {
fn from(value: $name) -> u8 {
match value {
$name::Unspecified => 0,
$( $name::$variant => $code, )+
$name::Other(code) => code,
}
}
}
};
}
code_enum! {
pub enum SensorType {
Temperature = 1,
Voltage = 2,
Fan = 4,
PowerSupply = 8,
}
}
code_enum! {
pub enum SensorUnit {
DegreesCelsius = 1,
Volts = 4,
Amps = 5,
Watts = 6,
Rpm = 18,
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum SensorState {
#[default]
Unspecified = 0,
Present = 1,
NotPresent = 2,
}
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct PowerSupplyFlag: u8 {
const PRESENCE_DETECTED = 1;
const FAILURE = 1 << 1;
const PREDICTIVE_FAILURE = 1 << 2;
const SOURCE_INPUT_LOST = 1 << 3;
const SOURCE_INPUT_OUT_OF_RANGE = 1 << 4;
const SOURCE_INPUT_DETECTED_OUT_OF_RANGE = 1 << 5;
const CONFIGURATION_ERROR = 1 << 6;
const STANDBY = 1 << 7;
}
}
#[derive(Debug, Clone, PartialEq, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[non_exhaustive]
pub struct Sensor {
pub id: usize,
pub name: String,
pub sensor_type: SensorType,
pub unit: SensorUnit,
pub state: SensorState,
pub flags: Option<PowerSupplyFlag>,
pub reading: f64,
pub lnr: f64,
pub lc: f64,
pub lnc: f64,
pub unc: f64,
pub uc: f64,
pub unr: f64,
}
#[derive(Debug, Clone, PartialEq, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[non_exhaustive]
pub struct PowerSupply {
pub id: usize,
pub name: String,
pub status: u8,
pub psu_type: u8,
pub input_voltage: u32,
pub input_current: f64,
pub input_power: u32,
pub output_voltage: f64,
pub output_current: f64,
pub output_power: u32,
pub temp_1: u32,
pub temp_2: u32,
pub fan_1: u32,
pub fan_2: u32,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn code_enums_round_trip() {
for code in 0..=u8::MAX {
assert_eq!(u8::from(SensorType::from(code)), code);
assert_eq!(u8::from(SensorUnit::from(code)), code);
}
assert_eq!(SensorType::from(8), SensorType::PowerSupply);
assert_eq!(SensorType::from(7), SensorType::Other(7));
assert_eq!(SensorUnit::from(18), SensorUnit::Rpm);
assert_eq!(SensorUnit::default(), SensorUnit::Unspecified);
}
#[test]
fn power_supply_flag_retains_unknown_bits() {
let flags = PowerSupplyFlag::from_bits_retain(0b1000_0011);
assert!(flags.contains(PowerSupplyFlag::PRESENCE_DETECTED | PowerSupplyFlag::FAILURE));
assert!(flags.contains(PowerSupplyFlag::STANDBY));
assert_eq!(flags.bits(), 0b1000_0011);
}
}