Fix ryzenadj build error with feature flag, try fix game start callbacks, start LED lib refactor
This commit is contained in:
parent
df71a619d9
commit
310af1b3ae
17 changed files with 337 additions and 146 deletions
9
backend/Cargo.lock
generated
9
backend/Cargo.lock
generated
|
@ -820,7 +820,6 @@ name = "limits_core"
|
|||
version = "3.0.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1069,6 +1068,7 @@ dependencies = [
|
|||
"log",
|
||||
"regex",
|
||||
"ron",
|
||||
"sd_led",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"simplelog",
|
||||
|
@ -1216,6 +1216,13 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
||||
|
||||
[[package]]
|
||||
name = "sd_led"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.183"
|
||||
|
|
|
@ -30,6 +30,7 @@ simplelog = "0.12"
|
|||
limits_core = { version = "3", path = "./limits_core" }
|
||||
regex = "1"
|
||||
libryzenadj = { version = "0.12" }
|
||||
sd_led = { version = "*", path = "./sd_led" }
|
||||
# ureq's tls feature does not like musl targets
|
||||
ureq = { version = "2", features = ["json", "gzip", "brotli", "charset"], default-features = false, optional = true }
|
||||
|
||||
|
@ -39,6 +40,7 @@ decky = ["usdpl-back/decky"]
|
|||
crankshaft = ["usdpl-back/crankshaft"]
|
||||
encrypt = ["usdpl-back/encrypt"]
|
||||
online = ["ureq"]
|
||||
experimental = []
|
||||
dev_stuff = []
|
||||
|
||||
[profile.release]
|
||||
|
|
24
backend/limits_core/Cargo.lock
generated
24
backend/limits_core/Cargo.lock
generated
|
@ -2,18 +2,11 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a"
|
||||
|
||||
[[package]]
|
||||
name = "limits_core"
|
||||
version = "3.0.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -34,12 +27,6 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.166"
|
||||
|
@ -60,17 +47,6 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.23"
|
||||
|
|
|
@ -7,4 +7,3 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
|
1
backend/limits_srv/Cargo.lock
generated
1
backend/limits_srv/Cargo.lock
generated
|
@ -436,7 +436,6 @@ name = "limits_core"
|
|||
version = "3.0.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
16
backend/sd_led/Cargo.lock
generated
Normal file
16
backend/sd_led/Cargo.lock
generated
Normal file
|
@ -0,0 +1,16 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||
|
||||
[[package]]
|
||||
name = "sd_led"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
10
backend/sd_led/Cargo.toml
Normal file
10
backend/sd_led/Cargo.toml
Normal file
|
@ -0,0 +1,10 @@
|
|||
[package]
|
||||
name = "sd_led"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
# logging
|
||||
log = "0.4"
|
193
backend/sd_led/src/lib.rs
Normal file
193
backend/sd_led/src/lib.rs
Normal file
|
@ -0,0 +1,193 @@
|
|||
//! Rough Rust port of some BatCtrl functionality
|
||||
//! Original: /usr/share/jupiter_controller_fw_updater/RA_bootloader_updater/linux_host_tools/BatCtrl
|
||||
//! I do not have access to the source code, so this is my own interpretation of what it does.
|
||||
//!
|
||||
//! But also Quanta is based in a place with some questionable copyright practices, so...
|
||||
pub mod raw_io;
|
||||
|
||||
use std::io::Error;
|
||||
|
||||
pub fn set_led(red_unused: bool, green_aka_white: bool, blue_unused: bool) -> Result<usize, Error> {
|
||||
let payload: u8 = 0x80
|
||||
| (red_unused as u8 & 1)
|
||||
| ((green_aka_white as u8 & 1) << 1)
|
||||
| ((blue_unused as u8 & 1) << 2);
|
||||
//log::info!("Payload: {:b}", payload);
|
||||
raw_io::write2(Setting::LEDStatus as _, payload)
|
||||
}
|
||||
|
||||
pub fn set(setting: Setting, mode: u8) -> Result<usize, Error> {
|
||||
raw_io::write2(setting as u8, mode)
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(u8)]
|
||||
pub enum Setting {
|
||||
CycleCount = 0x32,
|
||||
ControlBoard = 0x6C,
|
||||
Charge = 0xA6,
|
||||
ChargeMode = 0x76,
|
||||
LEDStatus = 199,
|
||||
LEDBreathing = 0x63,
|
||||
FanSpeed = 0x2c, // lower 3 bits seem to not do everything, every other bit increases speed -- 5 total steps, 0xf4 seems to do something similar too
|
||||
// 0x40 write 0x08 makes LED red + green turn on
|
||||
// 0x58 write 0x80 shuts off battery power (bms?)
|
||||
// 0x63 makes blue (0x02) or white (0x01) LED breathing effect
|
||||
// 0x7a write 0x01, 0x02, or 0x03 turns off display
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(u8)]
|
||||
pub enum ControlBoard {
|
||||
Enable = 0xAA,
|
||||
Disable = 0xAB,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(u8)]
|
||||
pub enum ChargeMode {
|
||||
Normal = 0,
|
||||
Discharge = 0x42,
|
||||
Idle = 0x45,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(u8)]
|
||||
pub enum Charge {
|
||||
Enable = 0,
|
||||
Disable = 4,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[allow(dead_code)]
|
||||
fn led_all_experiment_test() -> Result<(), Error> {
|
||||
let original = raw_io::write_read(Setting::LEDStatus as _)?;
|
||||
let sleep_dur = std::time::Duration::from_millis(1000);
|
||||
for b in 0..0x7F {
|
||||
let actual = 0x80 | b;
|
||||
raw_io::write2(Setting::LEDStatus as _, actual)?;
|
||||
println!("Wrote {actual:#b} to LED byte");
|
||||
std::thread::sleep(sleep_dur);
|
||||
}
|
||||
raw_io::write2(Setting::LEDStatus as _, original)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(dead_code)]
|
||||
fn led_singles_experiment_test() -> Result<(), Error> {
|
||||
let original = raw_io::write_read(Setting::LEDStatus as _)?;
|
||||
let sleep_dur = std::time::Duration::from_millis(1000);
|
||||
let mut value = 1;
|
||||
for _ in 0..std::mem::size_of::<u8>()*8 {
|
||||
let actual = 0x80 | value;
|
||||
raw_io::write2(Setting::LEDStatus as _, actual)?;
|
||||
println!("Wrote {actual:#b} to LED byte");
|
||||
value = value << 1;
|
||||
std::thread::sleep(sleep_dur);
|
||||
}
|
||||
raw_io::write2(Setting::LEDStatus as _, original)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(dead_code)]
|
||||
fn led_specify_experiment_test() -> Result<(), Error> {
|
||||
let mut buffer = String::new();
|
||||
println!("LED number(s) to display?");
|
||||
std::io::stdin().read_line(&mut buffer)?;
|
||||
|
||||
let mut resultant = 0;
|
||||
let original = raw_io::write_read(Setting::LEDStatus as _)?;
|
||||
for word in buffer.split(' ') {
|
||||
let trimmed_word = word.trim();
|
||||
if !trimmed_word.is_empty() {
|
||||
let value: u8 = trimmed_word.parse().expect("Invalid u8 number");
|
||||
let actual = 0x80 | value;
|
||||
raw_io::wait_ready_for_write()?;
|
||||
raw_io::write2(Setting::LEDStatus as _, actual)?;
|
||||
println!("Wrote {actual:#b} to LED byte");
|
||||
resultant |= actual;
|
||||
}
|
||||
}
|
||||
println!("Effectively wrote {resultant:#b} to LED byte");
|
||||
|
||||
println!("Press enter to return to normal");
|
||||
std::io::stdin().read_line(&mut buffer)?;
|
||||
raw_io::write2(Setting::LEDStatus as _, original)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(dead_code)]
|
||||
fn breath_specify_experiment_test() -> Result<(), Error> {
|
||||
let mut buffer = String::new();
|
||||
println!("LED number(s) to display?");
|
||||
std::io::stdin().read_line(&mut buffer)?;
|
||||
|
||||
for word in buffer.split(' ') {
|
||||
let trimmed_word = word.trim();
|
||||
if !trimmed_word.is_empty() {
|
||||
let value: u8 = trimmed_word.parse().expect("Invalid u8 number");
|
||||
let actual = 0x20 | value;
|
||||
raw_io::wait_ready_for_write()?;
|
||||
raw_io::write2(0x63, actual)?;
|
||||
println!("Wrote {actual:#b} to LED breathing byte");
|
||||
}
|
||||
}
|
||||
|
||||
println!("Press enter to return to normal");
|
||||
std::io::stdin().read_line(&mut buffer)?;
|
||||
raw_io::write2(0x63, 0)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(dead_code)]
|
||||
fn unmapped_ports_experiment_test() -> Result<(), Error> {
|
||||
let sleep_dur = std::time::Duration::from_millis(10000);
|
||||
let value = 0xaa;
|
||||
for addr in 0x63..0x64 {
|
||||
//raw_io::wait_ready_for_read()?;
|
||||
//let read = raw_io::write_read(addr)?;
|
||||
raw_io::wait_ready_for_write()?;
|
||||
raw_io::write2(addr, value)?;
|
||||
println!("wrote {value:#b} for {addr:#x} port");
|
||||
std::thread::sleep(sleep_dur);
|
||||
}
|
||||
//raw_io::write2(Setting::LEDStatus as _, 0)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(dead_code)]
|
||||
fn write_specify_experiment_test() -> Result<(), Error> {
|
||||
let mut buffer = String::new();
|
||||
println!("Register?");
|
||||
std::io::stdin().read_line(&mut buffer)?;
|
||||
let register: u8 = buffer.trim().parse().expect("Invalid u8 number");
|
||||
buffer.clear();
|
||||
|
||||
println!("Value(s)?");
|
||||
std::io::stdin().read_line(&mut buffer)?;
|
||||
|
||||
for word in buffer.split(' ') {
|
||||
let trimmed_word = word.trim();
|
||||
if !trimmed_word.is_empty() {
|
||||
let value: u8 = trimmed_word.parse().expect("Invalid u8 number");
|
||||
raw_io::wait_ready_for_write()?;
|
||||
raw_io::write2(register, value)?;
|
||||
println!("Wrote {value:#09b} to {register:#02x} register");
|
||||
}
|
||||
}
|
||||
|
||||
println!("Press enter to clear register");
|
||||
std::io::stdin().read_line(&mut buffer)?;
|
||||
raw_io::write2(register, 0)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
51
backend/sd_led/src/raw_io.rs
Normal file
51
backend/sd_led/src/raw_io.rs
Normal file
|
@ -0,0 +1,51 @@
|
|||
use std::fs::OpenOptions;
|
||||
use std::io::{Error, Read, Seek, SeekFrom, Write};
|
||||
|
||||
#[inline]
|
||||
pub fn write2(p0: u8, p1: u8) -> Result<usize, Error> {
|
||||
write_to(0x6c, 0x81)?;
|
||||
wait_ready_for_write()?;
|
||||
let count0 = write_to(0x68, p0)?;
|
||||
wait_ready_for_write()?;
|
||||
let count1 = write_to(0x68, p1)?;
|
||||
Ok(count0 + count1)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn write_read(p0: u8) -> Result<u8, Error> {
|
||||
write_to(0x6c, 0x81)?;
|
||||
wait_ready_for_write()?;
|
||||
write_to(0x68, p0)?;
|
||||
wait_ready_for_read()?;
|
||||
read_from(0x68)
|
||||
}
|
||||
|
||||
pub fn write_to(location: u64, value: u8) -> Result<usize, Error> {
|
||||
let mut file = OpenOptions::new().write(true).open("/dev/port")?;
|
||||
file.seek(SeekFrom::Start(location))?;
|
||||
file.write(&[value])
|
||||
}
|
||||
|
||||
pub fn read_from(location: u64) -> Result<u8, Error> {
|
||||
let mut file = OpenOptions::new().read(true).open("/dev/port")?;
|
||||
file.seek(SeekFrom::Start(location))?;
|
||||
let mut buffer = [0];
|
||||
file.read(&mut buffer)?;
|
||||
Ok(buffer[0])
|
||||
}
|
||||
|
||||
pub fn wait_ready_for_write() -> Result<(), Error> {
|
||||
let mut count = 0;
|
||||
while count < 0x1ffff && (read_from(0x6c)? & 2) != 0 {
|
||||
count += 1;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn wait_ready_for_read() -> Result<(), Error> {
|
||||
let mut count = 0;
|
||||
while count < 0x1ffff && (read_from(0x6c)? & 1) == 0 {
|
||||
count += 1;
|
||||
}
|
||||
Ok(())
|
||||
}
|
|
@ -8,6 +8,8 @@ use serde::{Deserialize, Serialize};
|
|||
pub struct GpuJson {
|
||||
pub fast_ppt: Option<u64>,
|
||||
pub slow_ppt: Option<u64>,
|
||||
pub tdp: Option<u64>,
|
||||
pub tdp_boost: Option<u64>,
|
||||
pub clock_limits: Option<MinMaxJson<u64>>,
|
||||
pub slow_memory: bool,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
|
@ -19,6 +21,8 @@ impl Default for GpuJson {
|
|||
Self {
|
||||
fast_ppt: None,
|
||||
slow_ppt: None,
|
||||
tdp: None,
|
||||
tdp_boost: None,
|
||||
clock_limits: None,
|
||||
slow_memory: false,
|
||||
root: None,
|
||||
|
|
|
@ -14,6 +14,8 @@ pub struct Gpu {
|
|||
pub slow_memory: bool,
|
||||
pub fast_ppt: Option<u64>,
|
||||
pub slow_ppt: Option<u64>,
|
||||
pub tdp: Option<u64>,
|
||||
pub tdp_boost: Option<u64>,
|
||||
pub clock_limits: Option<MinMax<u64>>,
|
||||
pub limits: GenericGpuLimit,
|
||||
sysfs: BasicEntityPath,
|
||||
|
@ -70,6 +72,16 @@ impl ProviderBuilder<GpuJson, GenericGpuLimit> for Gpu {
|
|||
} else {
|
||||
None
|
||||
},
|
||||
tdp: if limits.tdp.is_some() {
|
||||
persistent.tdp
|
||||
} else {
|
||||
None
|
||||
},
|
||||
tdp_boost: if limits.tdp_boost.is_some() {
|
||||
persistent.tdp_boost
|
||||
} else {
|
||||
None
|
||||
},
|
||||
clock_limits: clock_lims,
|
||||
limits,
|
||||
sysfs: Self::find_card_sysfs(persistent.root)
|
||||
|
@ -81,6 +93,8 @@ impl ProviderBuilder<GpuJson, GenericGpuLimit> for Gpu {
|
|||
slow_memory: false,
|
||||
fast_ppt: None,
|
||||
slow_ppt: None,
|
||||
tdp: None,
|
||||
tdp_boost: None,
|
||||
clock_limits: None,
|
||||
limits,
|
||||
sysfs: Self::find_card_sysfs(None::<&'static str>),
|
||||
|
@ -94,6 +108,8 @@ impl Into<GpuJson> for Gpu {
|
|||
GpuJson {
|
||||
fast_ppt: self.fast_ppt,
|
||||
slow_ppt: self.slow_ppt,
|
||||
tdp: self.tdp,
|
||||
tdp_boost: self.tdp_boost,
|
||||
clock_limits: self.clock_limits.map(|x| x.into()),
|
||||
slow_memory: false,
|
||||
root: self.sysfs.root().and_then(|p| p.as_ref().to_str().map(|s| s.to_owned()))
|
||||
|
|
|
@ -17,6 +17,7 @@ fn msg_or_err<D: std::fmt::Display, E: std::fmt::Display>(output: &mut String, m
|
|||
|
||||
fn log_capabilities(ryzenadj: &RyzenAdj) {
|
||||
log::info!("RyzenAdj v{}.{}.{}", libryzenadj::libryzenadj_sys::RYZENADJ_REVISION_VER, libryzenadj::libryzenadj_sys::RYZENADJ_MAJOR_VER, libryzenadj::libryzenadj_sys::RYZENADJ_MINIOR_VER);
|
||||
#[cfg(feature = "experimental")]
|
||||
if let Some(x) = ryzenadj.get_init_table_err() {
|
||||
log::warn!("RyzenAdj table init error: {}", x);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ use sysfuss::capability::attributes;
|
|||
|
||||
use limits_core::json_v2::GenericBatteryLimit;
|
||||
|
||||
use super::util::ChargeMode;
|
||||
use sd_led::ChargeMode;
|
||||
use crate::api::RangeLimit;
|
||||
use crate::persist::{BatteryEventJson, BatteryJson};
|
||||
use crate::settings::{TBattery, ProviderBuilder};
|
||||
|
@ -131,7 +131,7 @@ impl EventInstruction {
|
|||
|
||||
fn set_charge_mode(&self) -> Result<(), SettingError> {
|
||||
if let Some(charge_mode) = self.charge_mode {
|
||||
super::util::set(super::util::Setting::ChargeMode, charge_mode as _)
|
||||
sd_led::set(sd_led::Setting::ChargeMode, charge_mode as _)
|
||||
.map_err(|e| SettingError {
|
||||
msg: format!("Failed to set charge mode: {}", e),
|
||||
setting: crate::settings::SettingVariant::Battery,
|
||||
|
@ -329,7 +329,7 @@ impl Battery {
|
|||
fn set_charge_mode(&mut self) -> Result<(), SettingError> {
|
||||
if let Some(charge_mode) = self.charge_mode {
|
||||
self.state.charge_mode_set = true;
|
||||
super::util::set(super::util::Setting::ChargeMode, charge_mode as _)
|
||||
sd_led::set(sd_led::Setting::ChargeMode, charge_mode as _)
|
||||
.map_err(|e| SettingError {
|
||||
msg: format!("Failed to set charge mode: {}", e),
|
||||
setting: crate::settings::SettingVariant::Battery,
|
||||
|
@ -337,7 +337,7 @@ impl Battery {
|
|||
.map(|_| ())
|
||||
} else if self.state.charge_mode_set {
|
||||
self.state.charge_mode_set = false;
|
||||
super::util::set(super::util::Setting::ChargeMode, ChargeMode::Normal as _)
|
||||
sd_led::set(sd_led::Setting::ChargeMode, ChargeMode::Normal as _)
|
||||
.map_err(|e| SettingError {
|
||||
msg: format!("Failed to set charge mode: {}", e),
|
||||
setting: crate::settings::SettingVariant::Battery,
|
||||
|
|
|
@ -303,6 +303,8 @@ impl Into<GpuJson> for Gpu {
|
|||
GpuJson {
|
||||
fast_ppt: self.fast_ppt,
|
||||
slow_ppt: self.slow_ppt,
|
||||
tdp: None,
|
||||
tdp_boost: None,
|
||||
clock_limits: self.clock_limits.map(|x| x.into()),
|
||||
slow_memory: self.slow_memory,
|
||||
root: self.sysfs_card.root().or(self.sysfs_hwmon.root()).and_then(|p| p.as_ref().to_str().map(|r| r.to_owned()))
|
||||
|
|
|
@ -1,13 +1,5 @@
|
|||
//! Rough Rust port of some BatCtrl functionality
|
||||
//! Original: /usr/share/jupiter_controller_fw_updater/RA_bootloader_updater/linux_host_tools/BatCtrl
|
||||
//! I do not have access to the source code, so this is my own interpretation of what it does.
|
||||
//!
|
||||
//! But also Quanta is based in a place with some questionable copyright practices, so...
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::{Error, Read, Seek, SeekFrom, Write};
|
||||
|
||||
pub const JUPITER_HWMON_NAME: &'static str = "jupiter";
|
||||
pub const STEAMDECK_HWMON_NAME: &'static str = "steamdeck_hwmon";
|
||||
pub const GPU_HWMON_NAME: &'static str = "amdgpu";
|
||||
|
@ -25,63 +17,6 @@ pub fn card_also_has(card: &dyn sysfuss::SysEntity, extensions: &'static [&'stat
|
|||
.all(|ext| card.as_ref().join(ext).exists())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write2(p0: u8, p1: u8) -> Result<usize, Error> {
|
||||
write_to(0x6c, 0x81)?;
|
||||
wait_ready_for_write()?;
|
||||
let count0 = write_to(0x68, p0)?;
|
||||
wait_ready_for_write()?;
|
||||
let count1 = write_to(0x68, p1)?;
|
||||
Ok(count0 + count1)
|
||||
}
|
||||
|
||||
fn write_read(p0: u8) -> Result<u8, Error> {
|
||||
write_to(0x6c, 0x81)?;
|
||||
wait_ready_for_write()?;
|
||||
write_to(0x68, p0)?;
|
||||
wait_ready_for_read()?;
|
||||
read_from(0x68)
|
||||
}
|
||||
|
||||
fn write_to(location: u64, value: u8) -> Result<usize, Error> {
|
||||
let mut file = OpenOptions::new().write(true).open("/dev/port")?;
|
||||
file.seek(SeekFrom::Start(location))?;
|
||||
file.write(&[value])
|
||||
}
|
||||
|
||||
fn read_from(location: u64) -> Result<u8, Error> {
|
||||
let mut file = OpenOptions::new().read(true).open("/dev/port")?;
|
||||
file.seek(SeekFrom::Start(location))?;
|
||||
let mut buffer = [0];
|
||||
file.read(&mut buffer)?;
|
||||
Ok(buffer[0])
|
||||
}
|
||||
|
||||
fn wait_ready_for_write() -> Result<(), Error> {
|
||||
let mut count = 0;
|
||||
while count < 0x1ffff && (read_from(0x6c)? & 2) != 0 {
|
||||
count += 1;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn wait_ready_for_read() -> Result<(), Error> {
|
||||
let mut count = 0;
|
||||
while count < 0x1ffff && (read_from(0x6c)? & 1) == 0 {
|
||||
count += 1;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_led(red_unused: bool, green_aka_white: bool, blue_unused: bool) -> Result<usize, Error> {
|
||||
let payload: u8 = 0x80
|
||||
| (red_unused as u8 & 1)
|
||||
| ((green_aka_white as u8 & 1) << 1)
|
||||
| ((blue_unused as u8 & 1) << 2);
|
||||
//log::info!("Payload: {:b}", payload);
|
||||
write2(Setting::LEDStatus as _, payload)
|
||||
}
|
||||
|
||||
const THINGS: &[u8] = &[
|
||||
1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1,
|
||||
|
@ -92,55 +27,20 @@ const THINGS: &[u8] = &[
|
|||
const TIME_UNIT: std::time::Duration = std::time::Duration::from_millis(200);
|
||||
|
||||
pub fn flash_led() {
|
||||
let old_led_state = write_read(Setting::LEDStatus as _)
|
||||
let led_status = sd_led::Setting::LEDStatus;
|
||||
let old_led_state = sd_led::raw_io::write_read(led_status as _)
|
||||
.map_err(|e| log::error!("Failed to read LED status: {}", e));
|
||||
for &code in THINGS {
|
||||
let on = code != 0;
|
||||
if let Err(e) = set_led(on, on, false) {
|
||||
if let Err(e) = sd_led::set_led(on, on, false) {
|
||||
log::error!("Thing err: {}", e);
|
||||
}
|
||||
std::thread::sleep(TIME_UNIT);
|
||||
}
|
||||
if let Ok(old_led_state) = old_led_state {
|
||||
log::debug!("Restoring LED state to {:#02b}", old_led_state);
|
||||
write2(Setting::LEDStatus as _, old_led_state)
|
||||
sd_led::raw_io::write2(led_status as _, old_led_state)
|
||||
.map_err(|e| log::error!("Failed to restore LED status: {}", e))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set(setting: Setting, mode: u8) -> Result<usize, Error> {
|
||||
write2(setting as u8, mode)
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(u8)]
|
||||
pub enum Setting {
|
||||
CycleCount = 0x32,
|
||||
ControlBoard = 0x6C,
|
||||
Charge = 0xA6,
|
||||
ChargeMode = 0x76,
|
||||
LEDStatus = 199,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(u8)]
|
||||
pub enum ControlBoard {
|
||||
Enable = 0xAA,
|
||||
Disable = 0xAB,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(u8)]
|
||||
pub enum ChargeMode {
|
||||
Normal = 0,
|
||||
Discharge = 0x42,
|
||||
Idle = 0x45,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(u8)]
|
||||
pub enum Charge {
|
||||
Enable = 0,
|
||||
Disable = 4,
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@ impl Into<GpuJson> for Gpu {
|
|||
GpuJson {
|
||||
fast_ppt: None,
|
||||
slow_ppt: None,
|
||||
tdp: None,
|
||||
tdp_boost: None,
|
||||
clock_limits: None,
|
||||
slow_memory: false,
|
||||
root: None,
|
||||
|
|
|
@ -163,12 +163,20 @@ const reload = function() {
|
|||
backend.resolve(backend.getMessages(null), (messages: backend.Message[]) => { set_value(MESSAGE_LIST, messages) });
|
||||
};
|
||||
|
||||
// init USDPL WASM and connection to back-end
|
||||
(async function(){
|
||||
await backend.initBackend();
|
||||
usdplReady = true;
|
||||
reload(); // technically this is only a load
|
||||
const clearHooks = function() {
|
||||
clearInterval(periodicHook!);
|
||||
periodicHook = null;
|
||||
lifetimeHook?.unregister();
|
||||
startHook?.unregister();
|
||||
endHook?.unregister();
|
||||
|
||||
backend.log(backend.LogLevel.Debug, "Unregistered PowerTools callbacks, so long and thanks for all the fish.");
|
||||
};
|
||||
|
||||
const registerCallbacks = function(autoclear: boolean) {
|
||||
if (autoclear) {
|
||||
clearHooks();
|
||||
}
|
||||
// register Steam callbacks
|
||||
//@ts-ignore
|
||||
lifetimeHook = SteamClient.GameSessions.RegisterForAppLifetimeNotifications((update) => {
|
||||
|
@ -203,6 +211,15 @@ const reload = function() {
|
|||
});
|
||||
|
||||
backend.log(backend.LogLevel.Debug, "Registered PowerTools callbacks, hello!");
|
||||
};
|
||||
|
||||
// init USDPL WASM and connection to back-end
|
||||
(async function(){
|
||||
await backend.initBackend();
|
||||
usdplReady = true;
|
||||
reload(); // technically this is only a load
|
||||
|
||||
registerCallbacks(true);
|
||||
})();
|
||||
|
||||
const periodicals = function() {
|
||||
|
@ -334,19 +351,15 @@ export default definePlugin((serverApi: ServerAPI) => {
|
|||
if (now.getDate() == 1 && now.getMonth() == 3) {
|
||||
ico = <span><GiDynamite /><GiTimeTrap /><GiTimeBomb /></span>;
|
||||
}
|
||||
registerCallbacks(false);
|
||||
return {
|
||||
title: <div className={staticClasses.Title}>PowerTools</div>,
|
||||
content: <Content serverAPI={serverApi} />,
|
||||
icon: ico,
|
||||
onDismount() {
|
||||
backend.log(backend.LogLevel.Debug, "PowerTools shutting down");
|
||||
clearInterval(periodicHook!);
|
||||
periodicHook = null;
|
||||
lifetimeHook?.unregister();
|
||||
startHook?.unregister();
|
||||
endHook?.unregister();
|
||||
clearHooks();
|
||||
//serverApi.routerHook.removeRoute("/decky-plugin-test");
|
||||
backend.log(backend.LogLevel.Debug, "Unregistered PowerTools callbacks, so long and thanks for all the fish.");
|
||||
},
|
||||
};
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue