#![cfg(target_os = "macos")]
use crate::collect::model::FanTick;
#[derive(Debug, Clone, Default)]
pub struct MacosTick {
pub gpu_power_w: Option<f32>,
pub gpu_temp_c: Option<f32>,
pub system_power_w: Option<f32>,
pub cpu_power_w: Option<f32>,
pub ane_power_w: Option<f32>,
pub fans: Vec<FanTick>,
}
pub struct MacosSampler {
sampler: macpow::ioreport::IOReportSampler,
smc: macpow::smc::SmcConnection,
prev_sample: Option<macpow::ioreport::Sample>,
}
impl MacosSampler {
pub fn try_init() -> Option<Self> {
let sampler = macpow::ioreport::IOReportSampler::new().ok()?;
let mut smc = macpow::smc::SmcConnection::open().ok()?;
let handle = smc.start_temp_discovery();
smc.finish_temp_discovery(handle);
Some(Self {
sampler,
smc,
prev_sample: None,
})
}
pub fn tick(&mut self) -> MacosTick {
let mut out = MacosTick::default();
if let Ok(cur) = self.sampler.sample() {
if let Some(prev) = self.prev_sample.as_ref() {
if let Ok(power) = self.sampler.parse_power(prev, &cur) {
out.gpu_power_w = Some(power.gpu_w);
out.cpu_power_w = Some(power.cpu_w);
out.ane_power_w = Some(power.ane_w);
out.system_power_w = Some(power.total_w);
}
}
self.prev_sample = Some(cur);
}
let temps = self.smc.read_temperatures();
out.gpu_temp_c = temps
.iter()
.filter(|t| t.category == "GPU" && !t.stale)
.map(|t| t.value_celsius)
.fold(None, |acc, v| Some(acc.map_or(v, |a: f32| a.max(v))));
out.fans = self
.smc
.read_fans()
.into_iter()
.map(|f| FanTick {
name: if f.name.is_empty() {
format!("fan{}", f.id)
} else {
f.name
},
rpm: f.actual_rpm.max(0.0) as u32,
target_rpm: if f.max_rpm > 0.0 {
Some(f.max_rpm as u32)
} else {
None
},
})
.collect();
out
}
}