Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions UXTU4Linux/Assets/Modules/device_presets_loader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import json
import os
import subprocess

_PRESETS_FILE = os.path.join(os.path.dirname(os.path.dirname(__file__)), "device_presets.json")
_PRESETS_CACHE = None

def _load_presets():
global _PRESETS_CACHE
if _PRESETS_CACHE is not None:
return _PRESETS_CACHE
try:
if os.path.exists(_PRESETS_FILE):
with open(_PRESETS_FILE, "r") as f:
data = json.load(f)
_PRESETS_CACHE = data.get("devices", [])
return _PRESETS_CACHE
except Exception:
pass
return []

def _has_discrete_gpu(gpu_flag: str) -> bool:
try:
result = subprocess.run(
["lspci"],
capture_output=True, text=True, timeout=5,
)
lines = [l for l in result.stdout.splitlines() if "VGA" in l or "Display" in l]
vga = "\n".join(lines).lower()
return gpu_flag.lower() in vga
except Exception:
return False

def match_device(manufacturer: str, product_name: str) -> str:
devices = _load_presets()
mfr_lower = manufacturer.lower()
prod_lower = product_name.lower()

for device in devices:
# Check manufacturer
if "manufacturer_contains" in device:
if device["manufacturer_contains"].lower() not in mfr_lower:
continue

# Check product name ALL (AND condition)
if "product_name_contains" in device:
reqs = device["product_name_contains"]
if isinstance(reqs, list):
if not all(r.lower() in prod_lower for r in reqs):
continue
elif isinstance(reqs, str):
if reqs.lower() not in prod_lower:
continue

# Check product name ANY (OR condition)
if "product_name_contains_any" in device:
reqs = device["product_name_contains_any"]
if isinstance(reqs, list):
if not any(r.lower() in prod_lower for r in reqs):
continue

# Check discrete GPU requirement
if "requires_discrete_gpu" in device:
if not _has_discrete_gpu(device["requires_discrete_gpu"]):
continue

return device.get("variant_name", "")

return ""

def get_device_preset(variant_name: str) -> dict | None:
devices = _load_presets()
for device in devices:
if device.get("variant_name") == variant_name:
return device.get("preset")
return None
40 changes: 6 additions & 34 deletions UXTU4Linux/Assets/Modules/hardware.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,40 +381,12 @@ def _cpu_type(family: str, arch: str) -> str:
return "Amd_Apu"


def _lspci_vga() -> str:
try:
result = subprocess.run(
["lspci"],
capture_output=True, text=True, timeout=5,
)
lines = [l for l in result.stdout.splitlines() if "VGA" in l or "Display" in l]
return "\n".join(lines).lower()
except Exception:
return ""


def _has_discrete_rx7700s() -> bool:
vga = _lspci_vga()
return "7700s" in vga or "rx 7700s" in vga


def _detect_framework_variant() -> str:
def _detect_device_variant() -> str:
from .device_presets_loader import match_device
sys_raw = _dmi_raw("system")
product = _extract(sys_raw, "Product Name").lower()
mfr = _extract(sys_raw, "Manufacturer").lower()

if "framework" not in mfr:
return ""

if "laptop 16" in product and "7040" in product:
if _has_discrete_rx7700s():
return "AMDFrameworkLaptop16Ryzen7040_RX7700S"
return "AMDFrameworkLaptop16Ryzen7040"

if "laptop 13" in product and ("7040" in product or "ai 300" in product or "ryzen ai 300" in product):
return "AMDFrameworkLaptop13Ryzen7040_RyzenAI300"

return ""
product = _extract(sys_raw, "Product Name")
mfr = _extract(sys_raw, "Manufacturer")
return match_device(mfr, product)


def detect() -> None:
Expand All @@ -423,7 +395,7 @@ def detect() -> None:
cfg.set_config("Info", key, _dmi(field))
_compute_codename()

variant = _detect_framework_variant()
variant = _detect_device_variant()
cfg.set_config("Info", "Variant", variant)

cfg.save()
Expand Down
33 changes: 11 additions & 22 deletions UXTU4Linux/Assets/Modules/presets.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,28 +110,17 @@ def get_preset(cpu_type: str, family: str, cpu_model: str, raw_cpu: str, variant


def _variant_preset(variant: str) -> Preset | None:
match variant:
case "AMDFrameworkLaptop16Ryzen7040_RX7700S":
return Preset(
Eco="--tctl-temp=100 --apu-skin-temp=45 --stapm-limit=30000 --fast-limit=35000 --slow-limit=30000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000",
Balance="--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=95000 --fast-limit=95000 --slow-limit=95000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000",
Performance="--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=100000 --fast-limit=100000 --slow-limit=120000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000",
Extreme="--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=120000 --fast-limit=140000 --slow-limit=120000 --vrm-current=200000 --vrmmax-current=200000 --vrmsoc-current=200000 --vrmsocmax-current=200000 --vrmgfx-current=200000",
)
case "AMDFrameworkLaptop16Ryzen7040":
return Preset(
Eco="--tctl-temp=100 --apu-skin-temp=45 --stapm-limit=6000 --fast-limit=8000 --slow-limit=6000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000",
Balance="--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=35000 --fast-limit=45000 --slow-limit=38000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000",
Performance="--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=45000 --fast-limit=55000 --slow-limit=50000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000",
Extreme="--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=55000 --fast-limit=70000 --slow-limit=65000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000",
)
case "AMDFrameworkLaptop13Ryzen7040_RyzenAI300":
return Preset(
Eco="--tctl-temp=100 --apu-skin-temp=45 --stapm-limit=8000 --fast-limit=10000 --slow-limit=8000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000",
Balance="--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=15000 --fast-limit=18000 --slow-limit=15000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000",
Performance="--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=28000 --fast-limit=42000 --slow-limit=28000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000",
Extreme="--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=35000 --fast-limit=60000 --slow-limit=35000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000",
)
from .device_presets_loader import get_device_preset
preset_data = get_device_preset(variant)
if preset_data:
return Preset(
Eco=preset_data.get("Eco", ""),
Balance=preset_data.get("Balance", ""),
Performance=preset_data.get("Performance", ""),
Extreme=preset_data.get("Extreme", ""),
AC=preset_data.get("AC", "--max-performance"),
DC=preset_data.get("DC", "--power-saving")
)
return None


Expand Down
39 changes: 39 additions & 0 deletions UXTU4Linux/Assets/device_presets.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"devices": [
{
"manufacturer_contains": "framework",
"product_name_contains": ["laptop 16", "7040"],
"requires_discrete_gpu": "7700s",
"variant_name": "AMDFrameworkLaptop16Ryzen7040_RX7700S",
"preset": {
"Eco": "--tctl-temp=100 --apu-skin-temp=45 --stapm-limit=30000 --fast-limit=35000 --slow-limit=30000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000",
"Balance": "--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=95000 --fast-limit=95000 --slow-limit=95000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000",
"Performance": "--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=100000 --fast-limit=100000 --slow-limit=120000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000",
"Extreme": "--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=120000 --fast-limit=140000 --slow-limit=120000 --vrm-current=200000 --vrmmax-current=200000 --vrmsoc-current=200000 --vrmsocmax-current=200000 --vrmgfx-current=200000"
}
},
{
"manufacturer_contains": "framework",
"product_name_contains": ["laptop 16", "7040"],
"variant_name": "AMDFrameworkLaptop16Ryzen7040",
"preset": {
"Eco": "--tctl-temp=100 --apu-skin-temp=45 --stapm-limit=6000 --fast-limit=8000 --slow-limit=6000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000",
"Balance": "--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=35000 --fast-limit=45000 --slow-limit=38000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000",
"Performance": "--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=45000 --fast-limit=55000 --slow-limit=50000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000",
"Extreme": "--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=55000 --fast-limit=70000 --slow-limit=65000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000"
}
},
{
"manufacturer_contains": "framework",
"product_name_contains": ["laptop 13"],
"product_name_contains_any": ["7040", "ai 300", "ryzen ai 300"],
"variant_name": "AMDFrameworkLaptop13Ryzen7040_RyzenAI300",
"preset": {
"Eco": "--tctl-temp=100 --apu-skin-temp=45 --stapm-limit=8000 --fast-limit=10000 --slow-limit=8000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000",
"Balance": "--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=15000 --fast-limit=18000 --slow-limit=15000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000",
"Performance": "--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=28000 --fast-limit=42000 --slow-limit=28000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000",
"Extreme": "--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=35000 --fast-limit=60000 --slow-limit=35000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000"
}
}
]
}
Loading