use errno::{errno, Errno};
use num_enum::TryFromPrimitive;
use thiserror::Error;
pub use libryzenadj_sys_alt as libryzenadj_sys;
#[derive(Error, Debug)]
pub enum RyzenAdjError {
#[error("ryzenadj init failed: {} {}", errno, errno.0)]
InitError { errno: Errno },
#[error("ryzenadj table init failed: {0}, set functions might still work")]
InitTableError(i32),
#[error("ryzenadj get returned NaN")]
GetNaN,
#[error("ryzenadj familly: {0} is not know")]
UnknowFamily(i32),
#[error("ryzenadj adj family not supported")]
AdjFamilyNotSupported,
#[error("ryzenadj adj memory access error")]
AdjMemoryAccessError,
#[error("ryzenadj adj smu rejected")]
AdjSmuRejected,
#[error("ryzenadj adj smu timeout")]
AdjSmuTimeout,
#[error("ryzenadj adj smu unsupported")]
AdjSmuUnsupported,
#[error("ryzenadj adj unknow error {0}")]
AdjUnknowError(i32),
#[error("ryzenadj adj value out or range")]
AdjValueOutOfRange,
}
pub type RyzenAdjResult<T> = Result<T, RyzenAdjError>;
pub struct RyzenAdj {
ryzen_adj: libryzenadj_sys::ryzen_access,
init_table_result: Option<i32>,
}
#[derive(Debug, TryFromPrimitive)]
#[non_exhaustive]
#[repr(i32)]
pub enum RyzenFamily {
Unknow = libryzenadj_sys::ryzen_family_FAM_UNKNOWN,
Raven = libryzenadj_sys::ryzen_family_FAM_RAVEN,
Picassso = libryzenadj_sys::ryzen_family_FAM_PICASSO,
Renoir = libryzenadj_sys::ryzen_family_FAM_RENOIR,
Cezanne = libryzenadj_sys::ryzen_family_FAM_CEZANNE,
Dali = libryzenadj_sys::ryzen_family_FAM_DALI,
Lucienne = libryzenadj_sys::ryzen_family_FAM_LUCIENNE,
Vangogh = libryzenadj_sys::ryzen_family_FAM_VANGOGH,
Rembrandt = libryzenadj_sys::ryzen_family_FAM_REMBRANDT,
}
impl RyzenAdj {
pub fn new() -> RyzenAdjResult<Self> {
let ryzen_adj = unsafe { libryzenadj_sys::init_ryzenadj() };
if ryzen_adj.is_null() {
Err(RyzenAdjError::InitError { errno: errno() })
} else {
let init_table_result = unsafe { libryzenadj_sys::init_table(ryzen_adj) };
let init_table_result = if init_table_result != 0 {
Some(init_table_result)
} else {
None
};
Ok(Self {
ryzen_adj,
init_table_result,
})
}
}
fn is_init_table(&self) -> RyzenAdjResult<()> {
if let Some(init_table_result) = self.init_table_result {
Err(RyzenAdjError::InitTableError(init_table_result))
} else {
Ok(())
}
}
fn is_nan(value: f32) -> RyzenAdjResult<f32> {
if value.is_nan() {
Err(RyzenAdjError::GetNaN)
} else {
Ok(value)
}
}
fn adj_code(code: i32) -> RyzenAdjResult<()> {
match code {
0 => Ok(()),
libryzenadj_sys::ADJ_ERR_FAM_UNSUPPORTED => Err(RyzenAdjError::AdjFamilyNotSupported),
libryzenadj_sys::ADJ_ERR_MEMORY_ACCESS => Err(RyzenAdjError::AdjMemoryAccessError),
libryzenadj_sys::ADJ_ERR_SMU_REJECTED => Err(RyzenAdjError::AdjSmuRejected),
libryzenadj_sys::ADJ_ERR_SMU_TIMEOUT => Err(RyzenAdjError::AdjSmuTimeout),
libryzenadj_sys::ADJ_ERR_SMU_UNSUPPORTED => Err(RyzenAdjError::AdjSmuUnsupported),
_ => Err(RyzenAdjError::AdjUnknowError(code)),
}
}
pub fn refresh(&self) -> RyzenAdjResult<()> {
self.is_init_table()?;
let result = unsafe { libryzenadj_sys::refresh_table(self.ryzen_adj) };
if result != 0 {
Err(RyzenAdjError::InitTableError(result))
} else {
Ok(())
}
}
pub fn get_apu_skin_temp_limit(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_apu_skin_temp_limit(self.ryzen_adj) })
}
pub fn get_apu_skin_temp_value(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_apu_skin_temp_value(self.ryzen_adj) })
}
pub fn get_apu_slow_limit(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_apu_slow_limit(self.ryzen_adj) })
}
pub fn get_apu_slow_value(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_apu_slow_value(self.ryzen_adj) })
}
pub fn get_bios_if_ver(&self) -> RyzenAdjResult<i32> {
self.is_init_table()?;
Ok(unsafe { libryzenadj_sys::get_bios_if_ver(self.ryzen_adj) })
}
pub fn get_cclk_busy_value(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_cclk_busy_value(self.ryzen_adj) })
}
pub fn get_cclk_setpoint(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_cclk_setpoint(self.ryzen_adj) })
}
pub fn get_core_clk(&self, core: u32) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_core_clk(self.ryzen_adj, core) })
}
pub fn get_core_power(&self, core: u32) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_core_power(self.ryzen_adj, core) })
}
pub fn get_core_temp(&self, core: u32) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_core_temp(self.ryzen_adj, core) })
}
pub fn get_core_volt(&self, core: u32) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_core_volt(self.ryzen_adj, core) })
}
pub fn get_cpu_family(&self) -> RyzenAdjResult<RyzenFamily> {
self.is_init_table()?;
let family_int = unsafe { libryzenadj_sys::get_cpu_family(self.ryzen_adj) };
RyzenFamily::try_from(family_int).map_err(|_| RyzenAdjError::UnknowFamily(family_int))
}
pub fn get_dgpu_skin_temp_limit(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_dgpu_skin_temp_limit(self.ryzen_adj) })
}
pub fn get_dgpu_skin_temp_value(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_dgpu_skin_temp_value(self.ryzen_adj) })
}
pub fn get_fast_limit(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_fast_limit(self.ryzen_adj) })
}
pub fn get_fast_value(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_fast_value(self.ryzen_adj) })
}
pub fn get_fclk(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_fclk(self.ryzen_adj) })
}
pub fn get_gfx_temp(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_gfx_temp(self.ryzen_adj) })
}
pub fn get_gfx_clk(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_gfx_clk(self.ryzen_adj) })
}
pub fn get_gfx_volt(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_gfx_volt(self.ryzen_adj) })
}
pub fn get_l3_clk(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_l3_clk(self.ryzen_adj) })
}
pub fn get_l3_logic(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_l3_logic(self.ryzen_adj) })
}
pub fn get_l3_temp(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_l3_temp(self.ryzen_adj) })
}
pub fn get_l3_vddm(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_l3_vddm(self.ryzen_adj) })
}
pub fn get_mem_clk(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_mem_clk(self.ryzen_adj) })
}
pub fn get_psi0_current(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_psi0_current(self.ryzen_adj) })
}
pub fn get_psi0soc_current(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_psi0soc_current(self.ryzen_adj) })
}
pub fn get_slow_limit(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_slow_limit(self.ryzen_adj) })
}
pub fn get_slow_time(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_slow_time(self.ryzen_adj) })
}
pub fn get_slow_value(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_slow_value(self.ryzen_adj) })
}
pub fn get_soc_power(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_soc_power(self.ryzen_adj) })
}
pub fn get_soc_volt(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_soc_volt(self.ryzen_adj) })
}
pub fn get_socket_power(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_socket_power(self.ryzen_adj) })
}
pub fn get_stapm_limit(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_stapm_limit(self.ryzen_adj) })
}
pub fn get_stapm_time(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_stapm_time(self.ryzen_adj) })
}
pub fn get_stapm_value(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_stapm_value(self.ryzen_adj) })
}
pub fn get_tctl_temp(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_tctl_temp(self.ryzen_adj) })
}
pub fn get_tctl_temp_value(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_tctl_temp_value(self.ryzen_adj) })
}
pub fn get_vrm_current(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_vrm_current(self.ryzen_adj) })
}
pub fn get_vrm_current_value(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_vrm_current_value(self.ryzen_adj) })
}
pub fn get_vrmmax_current(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_vrmmax_current(self.ryzen_adj) })
}
pub fn get_vrmmax_current_value(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_vrmmax_current_value(self.ryzen_adj) })
}
pub fn get_vrmsoc_current(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_vrmsoc_current(self.ryzen_adj) })
}
pub fn get_vrmsoc_current_value(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_vrmsoc_current_value(self.ryzen_adj) })
}
pub fn get_vrmsocmax_current(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_vrmsocmax_current(self.ryzen_adj) })
}
pub fn get_vrmsocmax_current_value(&self) -> RyzenAdjResult<f32> {
self.is_init_table()?;
Self::is_nan(unsafe { libryzenadj_sys::get_vrmsocmax_current_value(self.ryzen_adj) })
}
pub fn set_apu_skin_temp_limit(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_apu_skin_temp_limit(self.ryzen_adj, value) })
}
pub fn set_apu_slow_limit(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_apu_slow_limit(self.ryzen_adj, value) })
}
pub unsafe fn set_unsafe_coall(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(libryzenadj_sys::set_coall(self.ryzen_adj, value))
}
pub unsafe fn set_unsafe_cogfx(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(libryzenadj_sys::set_cogfx(self.ryzen_adj, value))
}
pub unsafe fn set_unsafe_coper(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(libryzenadj_sys::set_coper(self.ryzen_adj, value))
}
pub fn set_coall(&self, value: i32) -> RyzenAdjResult<()> {
if (-30..=30).contains(&value) {
let value = 0x100000 + value;
Self::adj_code(unsafe { libryzenadj_sys::set_coall(self.ryzen_adj, value as u32) })
} else {
Err(RyzenAdjError::AdjValueOutOfRange)
}
}
pub fn set_coper(&self, core: u32, value: i32) -> RyzenAdjResult<()> {
if (-30..=30).contains(&value) {
let value = (core * 0x100000) as i32 + value;
Self::adj_code(unsafe { libryzenadj_sys::set_coper(self.ryzen_adj, value as u32) })
} else {
Err(RyzenAdjError::AdjValueOutOfRange)
}
}
pub fn set_dgpu_skin_temp_limit(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_coall(self.ryzen_adj, value) })
}
pub fn set_enable_oc(&self) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_enable_oc(self.ryzen_adj) })
}
pub fn set_disable_oc(&self) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_disable_oc(self.ryzen_adj) })
}
pub fn set_fast_limit(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_fast_limit(self.ryzen_adj, value) })
}
pub fn set_gfx_clk(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_gfx_clk(self.ryzen_adj, value) })
}
pub fn set_max_fclk_freq(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_max_fclk_freq(self.ryzen_adj, value) })
}
pub fn set_max_gfxclk_freq(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_max_gfxclk_freq(self.ryzen_adj, value) })
}
pub fn set_max_lclk(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_max_lclk(self.ryzen_adj, value) })
}
pub fn set_max_performance(&self) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_max_performance(self.ryzen_adj) })
}
pub fn set_max_socclk_freq(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_max_socclk_freq(self.ryzen_adj, value) })
}
pub fn set_max_vcn(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_max_vcn(self.ryzen_adj, value) })
}
pub fn set_min_fclk_freq(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_min_fclk_freq(self.ryzen_adj, value) })
}
pub fn set_min_gfxclk_freq(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_min_gfxclk_freq(self.ryzen_adj, value) })
}
pub fn set_min_lclk(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_min_lclk(self.ryzen_adj, value) })
}
pub fn set_min_socclk_freq(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_min_socclk_freq(self.ryzen_adj, value) })
}
pub fn set_min_vcn(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_min_vcn(self.ryzen_adj, value) })
}
pub fn set_oc_clk(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_oc_clk(self.ryzen_adj, value) })
}
pub fn set_oc_volt(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_oc_volt(self.ryzen_adj, value) })
}
pub fn set_per_core_oc_clk(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_per_core_oc_clk(self.ryzen_adj, value) })
}
pub fn set_power_saving(&self) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_power_saving(self.ryzen_adj) })
}
pub fn set_prochot_deassertion_ramp(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe {
libryzenadj_sys::set_prochot_deassertion_ramp(self.ryzen_adj, value)
})
}
pub fn set_psi0_current(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_psi0_current(self.ryzen_adj, value) })
}
pub fn set_psi0soc_current(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_psi0soc_current(self.ryzen_adj, value) })
}
pub fn set_psi3cpu_current(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_psi3cpu_current(self.ryzen_adj, value) })
}
pub fn set_psi3gfx_current(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_psi3gfx_current(self.ryzen_adj, value) })
}
pub fn set_skin_temp_power_limit(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_skin_temp_power_limit(self.ryzen_adj, value) })
}
pub fn set_slow_limit(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_slow_limit(self.ryzen_adj, value) })
}
pub fn set_slow_time(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_slow_time(self.ryzen_adj, value) })
}
pub fn set_stapm_limit(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_stapm_limit(self.ryzen_adj, value) })
}
pub fn set_stapm_time(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_stapm_time(self.ryzen_adj, value) })
}
pub fn set_tctl_temp(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_tctl_temp(self.ryzen_adj, value) })
}
pub fn set_vrm_current(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_vrm_current(self.ryzen_adj, value) })
}
pub fn set_vrmcvip_current(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_vrmcvip_current(self.ryzen_adj, value) })
}
pub fn set_vrmgfx_current(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_vrmgfx_current(self.ryzen_adj, value) })
}
pub fn set_vrmgfxmax_current(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_vrmgfxmax_current(self.ryzen_adj, value) })
}
pub fn set_vrmmax_current(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_vrmmax_current(self.ryzen_adj, value) })
}
pub fn set_vrmsoc_current(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_vrmsoc_current(self.ryzen_adj, value) })
}
pub fn set_vrmsocmax_current(&self, value: u32) -> RyzenAdjResult<()> {
Self::adj_code(unsafe { libryzenadj_sys::set_vrmsocmax_current(self.ryzen_adj, value) })
}
}
impl Drop for RyzenAdj {
fn drop(&mut self) {
unsafe {
libryzenadj_sys::cleanup_ryzenadj(self.ryzen_adj);
}
}
}